Skip to content

Commit 40db741

Browse files
Merge pull request #4 from nullinside-development-group/feat/chats-view
feat: connecting chat list to chat window
2 parents d6ee43f + bc69188 commit 40db741

File tree

14 files changed

+182
-48
lines changed

14 files changed

+182
-48
lines changed

.github/workflows/codeql.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
- name: Install .NET Core
3737
uses: actions/setup-dotnet@v3
3838
with:
39-
dotnet-version: 8.x.x
39+
dotnet-version: 9.x.x
4040

4141
# Execute the build
4242
- name: Execute Release Build
@@ -58,7 +58,7 @@ jobs:
5858
- name: Install .NET Core
5959
uses: actions/setup-dotnet@v3
6060
with:
61-
dotnet-version: 8.x.x
61+
dotnet-version: 9.x.x
6262

6363
# Execute the tests
6464
- name: Execute Tests
@@ -120,7 +120,7 @@ jobs:
120120
- name: Install .NET Core
121121
uses: actions/setup-dotnet@v3
122122
with:
123-
dotnet-version: 8.x.x
123+
dotnet-version: 9.x.x
124124

125125
# Execute the build
126126
- name: Execute Build

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
1+
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
22
USER $APP_UID
33
WORKDIR /app
44

5-
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
5+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
66
ARG BUILD_CONFIGURATION=Release
77
ARG TAG_VERSION
88
WORKDIR /src

Jenkinsfile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ pipeline {
1616
withCredentials([
1717
string(credentialsId: 'GITHUB_NULLINSIDE_ORG_RELEASE_TOKEN', variable: 'GITHUB_NULLINSIDE_ORG_RELEASE_TOKEN')
1818
]) {
19-
sh """
20-
bash go.sh
21-
"""
19+
script {
20+
def statusCode = sh script: "bash go.sh", returnStatus:true
21+
if (statusCode != 0) {
22+
error "Build Failed"
23+
}
24+
}
2225
}
2326
}
2427
}

src/TwitchStreamingTools/App.axaml.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
using System;
2+
using System.Threading.Tasks;
23

34
using Avalonia;
45
using Avalonia.Controls;
56
using Avalonia.Controls.ApplicationLifetimes;
67
using Avalonia.Markup.Xaml;
78

9+
using Nullinside.Api.Common.Twitch;
10+
11+
using TwitchStreamingTools.Models;
812
using TwitchStreamingTools.ViewModels;
913
using TwitchStreamingTools.Views;
1014

@@ -25,6 +29,9 @@ public override void Initialize() {
2529
/// Launches the main application window.
2630
/// </summary>
2731
public override void OnFrameworkInitializationCompleted() {
32+
TwitchClientProxy.Instance.TwitchOAuthToken = Configuration.Instance.OAuth?.Bearer;
33+
TwitchClientProxy.Instance.TwitchUsername = Configuration.Instance.TwitchUsername;
34+
2835
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) {
2936
desktop.MainWindow = new MainWindow {
3037
DataContext = new MainWindowViewModel()

src/TwitchStreamingTools/Constants.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ public static class Constants {
2020
public static string API_SITE_DOMAIN = "http://localhost:5036";
2121
#else
2222
/// <summary>
23-
/// The twitch app client id.
23+
/// The twitch app client id.
2424
/// </summary>
2525
public static string TWITCH_CLIENT_ID = "gi1eu8xu9tl6vkjqz4tjqkdzfmcq5h";
2626

2727
/// <summary>
28-
/// The domain that the api service is hosted at.
28+
/// The domain that the api service is hosted at.
2929
/// </summary>
3030
public static string API_SITE_DOMAIN = "https://nullinside.com";
3131
#endif

src/TwitchStreamingTools/Models/Configuration.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.IO;
34

45
using Newtonsoft.Json;
@@ -30,6 +31,11 @@ public static Configuration Instance {
3031
}
3132
}
3233

34+
/// <summary>
35+
/// The username of the user logged in through the <see cref="OAuth" /> token.
36+
/// </summary>
37+
public string? TwitchUsername { get; set; }
38+
3339
/// <summary>
3440
/// The twitch OAuth token.
3541
/// </summary>
@@ -40,6 +46,15 @@ public static Configuration Instance {
4046
/// </summary>
4147
public TwitchAppConfig? TwitchAppConfig { get; set; }
4248

49+
/// <summary>
50+
/// The collection of twitch chats we should read from.
51+
/// </summary>
52+
public IEnumerable<string>? TwitchChats { get; set; }
53+
54+
/// <summary>
55+
/// Reads the configuration from disk.
56+
/// </summary>
57+
/// <returns>The configuration if successful, null otherwise.</returns>
4358
private static Configuration? ReadConfiguration() {
4459
try {
4560
string json = File.ReadAllText(s_configLocation);

src/TwitchStreamingTools/TwitchStreamingTools.csproj

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<OutputType>WinExe</OutputType>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
77
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -11,6 +11,7 @@
1111
<PackageIcon>Assets\icon.png</PackageIcon>
1212
<RepositoryUrl>https://github.com/nullinside-development-group/nullinside-site-monitor</RepositoryUrl>
1313
<ApplicationIcon>Assets\logo.ico</ApplicationIcon>
14+
<LangVersion>default</LangVersion>
1415
</PropertyGroup>
1516
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
1617
<DocumentationFile>bin\Debug\TwitchStreamingTools.xml</DocumentationFile>
@@ -25,14 +26,14 @@
2526
</ItemGroup>
2627

2728
<ItemGroup>
28-
<PackageReference Include="Avalonia" Version="11.2.2"/>
29-
<PackageReference Include="Avalonia.Desktop" Version="11.2.2"/>
30-
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.2"/>
31-
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.2"/>
29+
<PackageReference Include="Avalonia" Version="11.2.8" />
30+
<PackageReference Include="Avalonia.Desktop" Version="11.2.8" />
31+
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.8" />
32+
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.8" />
3233
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
33-
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.2"/>
34-
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.2"/>
35-
<PackageReference Include="Material.Avalonia" Version="3.8.0"/>
34+
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.8" />
35+
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.8" />
36+
<PackageReference Include="Material.Avalonia" Version="3.10.2" />
3637
</ItemGroup>
3738

3839
<ItemGroup>

src/TwitchStreamingTools/Utilities/ClipboardPoller.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace TwitchStreamingTools.Utilities;
1010
/// <summary>
1111
/// Polls the clipboard looking for a specific JSON message.
1212
/// </summary>
13-
public class ClipboardPoller<T> : IClipboardPoller<T> {
13+
public class ClipboardPoller<T> : IClipboardPoller<T>, IDisposable {
1414
/// <summary>
1515
/// The callback to invoke when an OAuth token is found.
1616
/// </summary>
@@ -48,6 +48,11 @@ public void StopPolling() {
4848
_timer.Stop();
4949
}
5050

51+
/// <inheritdoc />
52+
public void Dispose() {
53+
_timer.Dispose();
54+
}
55+
5156
/// <summary>
5257
/// Checks the clipboard for our token.
5358
/// </summary>

src/TwitchStreamingTools/Utilities/TwitchApiWrapper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public static async Task<TwitchApiWrapper> CreateApi() {
4848
if (null != api.OAuth && !string.IsNullOrWhiteSpace(api.OAuth.AccessToken) &&
4949
!string.IsNullOrWhiteSpace(api.OAuth.RefreshToken)) {
5050
await api.RefreshAccessToken();
51+
(string? id, string? username) userInfo = await api.GetUser();
5152
Configuration.Instance.OAuth = new OAuthResponse {
5253
Bearer = api.OAuth.AccessToken,
5354
Refresh = api.OAuth.RefreshToken,

src/TwitchStreamingTools/ViewModels/Pages/AccountViewModel.cs

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
using Avalonia.Threading;
66

7+
using Nullinside.Api.Common.Twitch;
8+
79
using ReactiveUI;
810

911
using TwitchStreamingTools.Models;
@@ -14,21 +16,21 @@ namespace TwitchStreamingTools.ViewModels.Pages;
1416
/// <summary>
1517
/// Handles binding your account to the application.
1618
/// </summary>
17-
public class AccountViewModel : PageViewModelBase {
19+
public class AccountViewModel : PageViewModelBase, IDisposable {
1820
/// <summary>
19-
/// Polls the clipboard waiting for an oAuth configuration.
21+
/// The timer used to check the twitch OAuth token against the API.
2022
/// </summary>
21-
private IClipboardPoller<OAuthResponse>? _clipboardPoller;
23+
private readonly DispatcherTimer _timer;
2224

2325
/// <summary>
24-
/// True if we have a valid OAuth token, false otherwise.
26+
/// Polls the clipboard waiting for an oAuth configuration.
2527
/// </summary>
26-
private bool _hasValidOAuthToken;
28+
private IDisposable? _clipboardPoller;
2729

2830
/// <summary>
29-
/// The timer used to check the twitch OAuth token against the API.
31+
/// True if we have a valid OAuth token, false otherwise.
3032
/// </summary>
31-
private readonly DispatcherTimer _timer;
33+
private bool _hasValidOAuthToken;
3234

3335
/// <summary>
3436
/// The authenticated user's twitch username.
@@ -40,7 +42,7 @@ public class AccountViewModel : PageViewModelBase {
4042
/// </summary>
4143
public AccountViewModel() {
4244
OnLaunchBrowser = ReactiveCommand.Create(LaunchBrowser);
43-
OnLogout = ReactiveCommand.Create(Logout);
45+
OnLogout = ReactiveCommand.Create(ClearCredentials);
4446
_timer = new DispatcherTimer {
4547
Interval = TimeSpan.FromSeconds(5)
4648
};
@@ -79,18 +81,12 @@ public string? TwitchUsername {
7981
set => this.RaiseAndSetIfChanged(ref _twitchUsername, value);
8082
}
8183

82-
/// <summary>
83-
/// Handles logging out of the application.
84-
/// </summary>
85-
private void Logout() {
86-
try {
87-
Configuration.Instance.OAuth = null;
88-
Configuration.Instance.WriteConfiguration();
89-
OnCheckApiStatus();
90-
}
91-
catch {
92-
// do nothing
93-
}
84+
/// <inheritdoc />
85+
public void Dispose() {
86+
_timer.Stop();
87+
_clipboardPoller?.Dispose();
88+
OnLaunchBrowser.Dispose();
89+
OnLogout.Dispose();
9490
}
9591

9692
/// <summary>
@@ -100,14 +96,27 @@ private async void OnCheckApiStatus() {
10096
_timer.Stop();
10197
try {
10298
if (null == Configuration.Instance.OAuth?.Bearer) {
103-
TwitchUsername = null;
104-
HasValidOAuthToken = false;
99+
ClearCredentials();
105100
return;
106101
}
107102

108103
var api = await TwitchApiWrapper.CreateApi();
109104
TwitchUsername = (await api.GetUser()).username;
110105
HasValidOAuthToken = !string.IsNullOrWhiteSpace(TwitchUsername);
106+
107+
if (HasValidOAuthToken) {
108+
if (!string.Equals(api.OAuth?.AccessToken, Configuration.Instance.OAuth.Bearer) ||
109+
!string.Equals(TwitchUsername, Configuration.Instance.TwitchUsername)) {
110+
SetCredentials(TwitchUsername, new OAuthResponse {
111+
Bearer = api.OAuth!.AccessToken!,
112+
Refresh = api.OAuth.RefreshToken ?? string.Empty,
113+
ExpiresUtc = api.OAuth.ExpiresUtc ?? DateTime.MinValue
114+
});
115+
}
116+
}
117+
else {
118+
ClearCredentials();
119+
}
111120
}
112121
catch {
113122
TwitchUsername = null;
@@ -122,8 +131,9 @@ private async void OnCheckApiStatus() {
122131
/// Launches the computer's default browser to generate an OAuth token.
123132
/// </summary>
124133
private void LaunchBrowser() {
125-
Configuration.Instance.OAuth = null;
126-
Configuration.Instance.WriteConfiguration();
134+
if (null != _clipboardPoller) {
135+
_clipboardPoller.Dispose();
136+
}
127137

128138
_clipboardPoller = new ClipboardPoller<OAuthResponse>(Constants.CLIPBOARD!, OnOAuthReceived);
129139

@@ -140,12 +150,31 @@ private void LaunchBrowser() {
140150
/// <param name="oauth">The new OAuth token.</param>
141151
private void OnOAuthReceived(OAuthResponse oauth) {
142152
try {
143-
Configuration.Instance.OAuth = oauth;
144-
Configuration.Instance.WriteConfiguration();
153+
SetCredentials(null, oauth);
145154
OnCheckApiStatus();
146155
}
147156
catch {
148157
// do nothing
149158
}
150159
}
160+
161+
private void ClearCredentials() {
162+
TwitchUsername = null;
163+
HasValidOAuthToken = false;
164+
TwitchClientProxy.Instance.Dispose();
165+
166+
if (null != Configuration.Instance.OAuth) {
167+
Configuration.Instance.OAuth = null;
168+
Configuration.Instance.TwitchUsername = null;
169+
Configuration.Instance.WriteConfiguration();
170+
}
171+
}
172+
173+
private void SetCredentials(string? username, OAuthResponse oauth) {
174+
Configuration.Instance.OAuth = oauth;
175+
Configuration.Instance.TwitchUsername = username;
176+
Configuration.Instance.WriteConfiguration();
177+
TwitchClientProxy.Instance.TwitchUsername = username;
178+
TwitchClientProxy.Instance.TwitchOAuthToken = oauth.Bearer;
179+
}
151180
}

0 commit comments

Comments
 (0)