Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
c2309599f2 | |||
4ac3a44cef | |||
b42d313bff | |||
019649b179 | |||
2fcf63cf86 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,6 +20,7 @@
|
|||||||
mono_crash.*
|
mono_crash.*
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
|
[Bb]iuld/
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
|
207
App.axaml.cs
207
App.axaml.cs
@ -5,142 +5,211 @@ using Avalonia;
|
|||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Data.Core.Plugins;
|
using Avalonia.Data.Core.Plugins;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using BetterRaid.Services;
|
||||||
using BetterRaid.ViewModels;
|
using BetterRaid.ViewModels;
|
||||||
using BetterRaid.Views;
|
using BetterRaid.Views;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using TwitchLib.Api;
|
using TwitchLib.Api;
|
||||||
|
|
||||||
namespace BetterRaid;
|
namespace BetterRaid;
|
||||||
|
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
internal static TwitchAPI? TwitchApi = null;
|
private readonly ServiceCollection _services = [];
|
||||||
internal static int AutoUpdateDelay = 10_000;
|
private ServiceProvider? _provider;
|
||||||
internal static bool HasUserZnSubbed = false;
|
|
||||||
internal static string BetterRaidDataPath = "";
|
private static TwitchAPI? _twitchApi;
|
||||||
internal static string TwitchBroadcasterId = "";
|
private static bool _hasUserZnSubbed;
|
||||||
internal static string TwitchOAuthAccessToken = "";
|
private static string _betterRaidDataPath = "";
|
||||||
internal static string TwitchOAuthAccessTokenFilePath = "";
|
private static string _twitchBroadcasterId = "";
|
||||||
internal static string TokenClientId = "kkxu4jorjrrc5jch1ito5i61hbev2o";
|
private static string _twitchOAuthAccessToken = "";
|
||||||
internal static readonly string TwitchOAuthRedirectUrl = "http://localhost:9900";
|
private static string _twitchOAuthAccessTokenFilePath = "";
|
||||||
internal static readonly string TwitchOAuthResponseType = "token";
|
private const string TokenClientId = "kkxu4jorjrrc5jch1ito5i61hbev2o";
|
||||||
internal static readonly string[] TwitchOAuthScopes = [
|
private const string TwitchOAuthRedirectUrl = "http://localhost:9900";
|
||||||
|
private const string TwitchOAuthResponseType = "token";
|
||||||
|
|
||||||
|
private static readonly string[] TwitchOAuthScopes = [
|
||||||
"channel:manage:raids",
|
"channel:manage:raids",
|
||||||
"user:read:subscriptions"
|
"user:read:subscriptions"
|
||||||
];
|
];
|
||||||
|
|
||||||
internal static readonly string TwitchOAuthUrl = $"https://id.twitch.tv/oauth2/authorize"
|
internal static readonly string TwitchOAuthUrl = $"https://id.twitch.tv/oauth2/authorize"
|
||||||
+ $"?client_id={TokenClientId}"
|
+ $"?client_id={TokenClientId}"
|
||||||
+ "&redirect_uri=http://localhost:9900"
|
+ $"&redirect_uri={TwitchOAuthRedirectUrl}"
|
||||||
+ $"&response_type={TwitchOAuthResponseType}"
|
+ $"&response_type={TwitchOAuthResponseType}"
|
||||||
+ $"&scope={string.Join("+", TwitchOAuthScopes)}";
|
+ $"&scope={string.Join("+", TwitchOAuthScopes)}";
|
||||||
|
|
||||||
|
public const string ChannelPlaceholderImageUrl = "https://cdn.pixabay.com/photo/2018/11/13/22/01/avatar-3814081_1280.png";
|
||||||
|
|
||||||
|
public static TwitchAPI? TwitchApi => _twitchApi;
|
||||||
|
public static bool HasUserZnSubbed => _hasUserZnSubbed;
|
||||||
|
|
||||||
|
public IServiceProvider? Provider => _provider;
|
||||||
|
public static string? TwitchBroadcasterId => _twitchBroadcasterId;
|
||||||
|
|
||||||
|
public static string TwitchOAuthAccessToken
|
||||||
|
{
|
||||||
|
get => _twitchOAuthAccessToken;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_twitchOAuthAccessToken = value;
|
||||||
|
InitTwitchClient(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
InitializeServices();
|
||||||
|
LoadTwitchToken();
|
||||||
|
|
||||||
|
AvaloniaXamlLoader.Load(_provider, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTwitchToken()
|
||||||
{
|
{
|
||||||
var userHomeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
var userHomeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
|
|
||||||
switch (Environment.OSVersion.Platform)
|
_betterRaidDataPath = Environment.OSVersion.Platform switch
|
||||||
{
|
{
|
||||||
case PlatformID.Win32NT:
|
PlatformID.Win32NT => Path.Combine(userHomeDir, "AppData", "Roaming", "BetterRaid"),
|
||||||
BetterRaidDataPath = Path.Combine(userHomeDir, "AppData", "Roaming", "BetterRaid");
|
PlatformID.Unix => Path.Combine(userHomeDir, ".config", "BetterRaid"),
|
||||||
break;
|
PlatformID.MacOSX => Path.Combine(userHomeDir, "Library", "Application Support", "BetterRaid"),
|
||||||
case PlatformID.Unix:
|
_ => throw new PlatformNotSupportedException($"Your platform '{Environment.OSVersion.Platform}' is not supported. Please report this issue here: https://www.github.com/zion-networks/BetterRaid/issues")
|
||||||
BetterRaidDataPath = Path.Combine(userHomeDir, ".config", "BetterRaid");
|
};
|
||||||
break;
|
|
||||||
case PlatformID.MacOSX:
|
if (!Directory.Exists(_betterRaidDataPath))
|
||||||
BetterRaidDataPath = Path.Combine(userHomeDir, "Library", "Application Support", "BetterRaid");
|
{
|
||||||
break;
|
var di = Directory.CreateDirectory(_betterRaidDataPath);
|
||||||
|
if (di.Exists == false)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to create directory '{_betterRaidDataPath}'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Directory.Exists(BetterRaidDataPath))
|
_twitchOAuthAccessTokenFilePath = Path.Combine(_betterRaidDataPath, ".access_token");
|
||||||
Directory.CreateDirectory(BetterRaidDataPath);
|
|
||||||
|
|
||||||
TwitchOAuthAccessTokenFilePath = Path.Combine(BetterRaidDataPath, ".access_token");
|
if (!File.Exists(_twitchOAuthAccessTokenFilePath))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_twitchOAuthAccessToken = File.ReadAllText(_twitchOAuthAccessTokenFilePath);
|
||||||
|
InitTwitchClient();
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(TwitchOAuthAccessTokenFilePath))
|
private void InitializeServices()
|
||||||
{
|
{
|
||||||
TwitchOAuthAccessToken = File.ReadAllText(TwitchOAuthAccessTokenFilePath);
|
_services.AddSingleton<ITwitchDataService, TwitchDataService>();
|
||||||
InitTwitchClient();
|
_services.AddTransient<MainWindowViewModel>();
|
||||||
}
|
_services.AddTransient<AboutWindowViewModel>();
|
||||||
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
_provider = _services.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitTwitchClient(bool overrideToken = false)
|
public static void InitTwitchClient(bool overrideToken = false)
|
||||||
{
|
{
|
||||||
Console.WriteLine("[INFO] Initializing Twitch Client...");
|
Console.WriteLine("[INFO] Initializing Twitch Client...");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_twitchOAuthAccessToken))
|
||||||
|
{
|
||||||
|
Console.WriteLine("[ERROR] Failed to initialize Twitch Client: Access Token is empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TwitchApi = new TwitchAPI();
|
_twitchApi = new TwitchAPI
|
||||||
TwitchApi.Settings.ClientId = TokenClientId;
|
{
|
||||||
TwitchApi.Settings.AccessToken = TwitchOAuthAccessToken;
|
Settings =
|
||||||
|
{
|
||||||
|
ClientId = TokenClientId,
|
||||||
|
AccessToken = _twitchOAuthAccessToken
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Console.WriteLine("[INFO] Testing Twitch API connection...");
|
Console.WriteLine("[INFO] Testing Twitch API connection...");
|
||||||
|
|
||||||
var user = TwitchApi.Helix.Users.GetUsersAsync().Result.Users.FirstOrDefault();
|
var user = _twitchApi.Helix.Users.GetUsersAsync().Result.Users.FirstOrDefault();
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
TwitchApi = null;
|
_twitchApi = null;
|
||||||
Console.WriteLine("[ERROR] Failed to connect to Twitch API!");
|
Console.WriteLine("[ERROR] Failed to connect to Twitch API!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var channel = TwitchApi.Helix.Search
|
var channel = _twitchApi.Helix.Search
|
||||||
.SearchChannelsAsync(user.Login).Result.Channels
|
.SearchChannelsAsync(user.Login).Result.Channels
|
||||||
.FirstOrDefault(c => c.BroadcasterLogin == user.Login);
|
.FirstOrDefault(c => c.BroadcasterLogin == user.Login);
|
||||||
|
|
||||||
var userSubs = TwitchApi.Helix.Subscriptions.CheckUserSubscriptionAsync(
|
var userSubs = _twitchApi.Helix.Subscriptions.CheckUserSubscriptionAsync(
|
||||||
userId: user.Id,
|
userId: user.Id,
|
||||||
broadcasterId: "1120558409"
|
broadcasterId: "1120558409"
|
||||||
).Result.Data;
|
).Result.Data;
|
||||||
|
|
||||||
if (userSubs.Length > 0 && userSubs.Any(s => s.BroadcasterId == "1120558409"))
|
if (userSubs is { Length: > 0 } && userSubs.Any(s => s.BroadcasterId == "1120558409"))
|
||||||
{
|
{
|
||||||
HasUserZnSubbed = true;
|
_hasUserZnSubbed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("[ERROR] User channel could not be found!");
|
Console.WriteLine($"[ERROR] Failed to get channel information for '{user.Login}'!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TwitchBroadcasterId = channel.Id;
|
_twitchBroadcasterId = channel.Id;
|
||||||
System.Console.WriteLine(TwitchBroadcasterId);
|
Console.WriteLine(_twitchBroadcasterId);
|
||||||
|
|
||||||
Console.WriteLine("[INFO] Connected to Twitch API as '{0}'!", user.DisplayName);
|
Console.WriteLine("[INFO] Connected to Twitch API as '{0}'!", user.DisplayName);
|
||||||
|
|
||||||
if (overrideToken)
|
if (!overrideToken)
|
||||||
{
|
return;
|
||||||
File.WriteAllText(TwitchOAuthAccessTokenFilePath, TwitchOAuthAccessToken);
|
|
||||||
|
File.WriteAllText(_twitchOAuthAccessTokenFilePath, _twitchOAuthAccessToken);
|
||||||
|
|
||||||
switch (Environment.OSVersion.Platform)
|
switch (Environment.OSVersion.Platform)
|
||||||
{
|
{
|
||||||
case PlatformID.Win32NT:
|
case PlatformID.Win32NT:
|
||||||
File.SetAttributes(TwitchOAuthAccessTokenFilePath, File.GetAttributes(TwitchOAuthAccessTokenFilePath) | FileAttributes.Hidden);
|
File.SetAttributes(_twitchOAuthAccessTokenFilePath, File.GetAttributes(_twitchOAuthAccessTokenFilePath) | FileAttributes.Hidden);
|
||||||
break;
|
break;
|
||||||
case PlatformID.Unix:
|
|
||||||
|
case PlatformID.Unix:
|
||||||
#pragma warning disable CA1416 // Validate platform compatibility
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||||
File.SetUnixFileMode(TwitchOAuthAccessTokenFilePath, UnixFileMode.UserRead);
|
File.SetUnixFileMode(_twitchOAuthAccessTokenFilePath, UnixFileMode.UserRead);
|
||||||
#pragma warning restore CA1416 // Validate platform compatibility
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||||
break;
|
break;
|
||||||
case PlatformID.MacOSX:
|
|
||||||
File.SetAttributes(TwitchOAuthAccessTokenFilePath, File.GetAttributes(TwitchOAuthAccessTokenFilePath) | FileAttributes.Hidden);
|
case PlatformID.MacOSX:
|
||||||
break;
|
File.SetAttributes(_twitchOAuthAccessTokenFilePath, File.GetAttributes(_twitchOAuthAccessTokenFilePath) | FileAttributes.Hidden);
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new PlatformNotSupportedException($"Your platform '{Environment.OSVersion.Platform}' is not supported. Please report this issue here: https://www.github.com/zion-networks/BetterRaid/issues");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
{
|
{
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
BindingPlugins.DataValidators.RemoveAt(0);
|
||||||
|
|
||||||
|
var vm = _provider?.GetRequiredService<MainWindowViewModel>();
|
||||||
|
|
||||||
|
switch (ApplicationLifetime)
|
||||||
{
|
{
|
||||||
// Line below is needed to remove Avalonia data validation.
|
case IClassicDesktopStyleApplicationLifetime desktop:
|
||||||
// Without this line you will get duplicate validations from both Avalonia and CT
|
// Line below is needed to remove Avalonia data validation.
|
||||||
BindingPlugins.DataValidators.RemoveAt(0);
|
// Without this line you will get duplicate validations from both Avalonia and CT
|
||||||
desktop.MainWindow = new MainWindow
|
|
||||||
{
|
desktop.MainWindow = new MainWindow
|
||||||
DataContext = new MainWindowViewModel(),
|
{
|
||||||
};
|
DataContext = vm
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ISingleViewApplicationLifetime singleViewPlatform:
|
||||||
|
singleViewPlatform.MainView = new MainWindow
|
||||||
|
{
|
||||||
|
DataContext = vm
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
base.OnFrameworkInitializationCompleted();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,6 +27,7 @@
|
|||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--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 Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.0" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageReference Include="TwitchLib" Version="3.5.3" />
|
<PackageReference Include="TwitchLib" Version="3.5.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.5.002.0
|
VisualStudioVersion = 17.5.002.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterRaid", "BetterRaid.csproj", "{77D4100D-424A-4E36-BFF2-14A40F217605}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterRaid", "BetterRaid.csproj", "{49E459C8-9DCF-4D6D-95FC-75303243F248}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -11,10 +11,10 @@ Global
|
|||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{77D4100D-424A-4E36-BFF2-14A40F217605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{49E459C8-9DCF-4D6D-95FC-75303243F248}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{77D4100D-424A-4E36-BFF2-14A40F217605}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{49E459C8-9DCF-4D6D-95FC-75303243F248}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{77D4100D-424A-4E36-BFF2-14A40F217605}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{49E459C8-9DCF-4D6D-95FC-75303243F248}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{77D4100D-424A-4E36-BFF2-14A40F217605}.Release|Any CPU.Build.0 = Release|Any CPU
|
{49E459C8-9DCF-4D6D-95FC-75303243F248}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -1,11 +1,22 @@
|
|||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace BetterRaid.Extensions;
|
namespace BetterRaid.Extensions;
|
||||||
|
|
||||||
public static class DataContextExtensions
|
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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Avalonia.Threading;
|
|
||||||
|
|
||||||
namespace BetterRaid.Models;
|
namespace BetterRaid.Models;
|
||||||
|
|
||||||
@ -12,6 +12,8 @@ public class TwitchChannel : INotifyPropertyChanged
|
|||||||
private string? _displayName;
|
private string? _displayName;
|
||||||
private string? _thumbnailUrl;
|
private string? _thumbnailUrl;
|
||||||
private string? _category;
|
private string? _category;
|
||||||
|
private string? _title;
|
||||||
|
private DateTime? _lastRaided;
|
||||||
|
|
||||||
public string? BroadcasterId
|
public string? BroadcasterId
|
||||||
{
|
{
|
||||||
@ -93,6 +95,32 @@ public class TwitchChannel : INotifyPropertyChanged
|
|||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _title)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_title = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? LastRaided
|
||||||
|
{
|
||||||
|
get => _lastRaided;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _lastRaided)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_lastRaided = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TwitchChannel(string channelName)
|
public TwitchChannel(string channelName)
|
||||||
{
|
{
|
||||||
|
@ -9,8 +9,9 @@ sealed class Program
|
|||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
// yet and stuff might break.
|
// yet and stuff might break.
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
public static void Main(string[] args) =>
|
||||||
.StartWithClassicDesktopLifetime(args);
|
BuildAvaloniaApp()
|
||||||
|
.StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
public static AppBuilder BuildAvaloniaApp()
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
|
6
Services/ITwitchDataService.cs
Normal file
6
Services/ITwitchDataService.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace BetterRaid.Services;
|
||||||
|
|
||||||
|
public interface ITwitchDataService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
6
Services/Implementations/TwitchDataService.cs
Normal file
6
Services/Implementations/TwitchDataService.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace BetterRaid.Services;
|
||||||
|
|
||||||
|
public class TwitchDataService : ITwitchDataService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
13
ViewModels/AboutWindowViewModel.cs
Normal file
13
ViewModels/AboutWindowViewModel.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace BetterRaid.ViewModels;
|
namespace BetterRaid.ViewModels;
|
||||||
|
|
||||||
public class AddChannelWindowViewModel : ViewModelBase
|
public class AddChannelWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
|
public AddChannelWindowViewModel()
|
||||||
|
{
|
||||||
|
Console.WriteLine("[DEBUG] AddChannelWindowViewModel created");
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using BetterRaid.Extensions;
|
using BetterRaid.Extensions;
|
||||||
using BetterRaid.Misc;
|
using BetterRaid.Misc;
|
||||||
using BetterRaid.Models;
|
using BetterRaid.Models;
|
||||||
|
using BetterRaid.Services;
|
||||||
using BetterRaid.Views;
|
using BetterRaid.Views;
|
||||||
|
|
||||||
namespace BetterRaid.ViewModels;
|
namespace BetterRaid.ViewModels;
|
||||||
@ -11,13 +14,25 @@ namespace BetterRaid.ViewModels;
|
|||||||
public partial class MainWindowViewModel : ViewModelBase
|
public partial class MainWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private string? _filter;
|
private string? _filter;
|
||||||
|
private ObservableCollection<TwitchChannel> _channels = [];
|
||||||
private BetterRaidDatabase? _db;
|
private BetterRaidDatabase? _db;
|
||||||
|
|
||||||
public BetterRaidDatabase? Database
|
public BetterRaidDatabase? Database
|
||||||
{
|
{
|
||||||
get => _db;
|
get => _db;
|
||||||
set => SetProperty(ref _db, value);
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _db, value) && _db != null)
|
||||||
|
{
|
||||||
|
LoadChannelsFromDb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<TwitchChannel> Channels
|
||||||
|
{
|
||||||
|
get => _channels;
|
||||||
|
set => SetProperty(ref _channels, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? Filter
|
public string? Filter
|
||||||
@ -28,6 +43,12 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
|
|
||||||
public bool IsLoggedIn => App.TwitchApi != null;
|
public bool IsLoggedIn => App.TwitchApi != null;
|
||||||
|
|
||||||
|
public MainWindowViewModel(ITwitchDataService t)
|
||||||
|
{
|
||||||
|
Console.WriteLine(t);
|
||||||
|
Console.WriteLine("[DEBUG] MainWindowViewModel created");
|
||||||
|
}
|
||||||
|
|
||||||
public void ExitApplication()
|
public void ExitApplication()
|
||||||
{
|
{
|
||||||
//TODO polish later
|
//TODO polish later
|
||||||
@ -37,6 +58,7 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
public void ShowAboutWindow(Window owner)
|
public void ShowAboutWindow(Window owner)
|
||||||
{
|
{
|
||||||
var about = new AboutWindow();
|
var about = new AboutWindow();
|
||||||
|
about.InjectDataContext<AboutWindowViewModel>();
|
||||||
about.ShowDialog(owner);
|
about.ShowDialog(owner);
|
||||||
about.CenterToOwner();
|
about.CenterToOwner();
|
||||||
}
|
}
|
||||||
@ -46,10 +68,27 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
Tools.StartOAuthLogin(App.TwitchOAuthUrl, OnTwitchLoginCallback, CancellationToken.None);
|
Tools.StartOAuthLogin(App.TwitchOAuthUrl, OnTwitchLoginCallback, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTwitchLoginCallback()
|
private void OnTwitchLoginCallback()
|
||||||
{
|
{
|
||||||
App.InitTwitchClient(overrideToken: true);
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(IsLoggedIn));
|
OnPropertyChanged(nameof(IsLoggedIn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadChannelsFromDb()
|
||||||
|
{
|
||||||
|
if (_db == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Channels.Clear();
|
||||||
|
|
||||||
|
var channels = _db.Channels
|
||||||
|
.Select(channelName => new TwitchChannel(channelName))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var c in channels)
|
||||||
|
{
|
||||||
|
Channels.Add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@ namespace BetterRaid.ViewModels;
|
|||||||
|
|
||||||
public class ViewModelBase : ObservableObject
|
public class ViewModelBase : ObservableObject
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="clr-namespace:BetterRaid.ViewModels"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="BetterRaid.Views.AboutWindow"
|
x:Class="BetterRaid.Views.AboutWindow"
|
||||||
|
x:DataType="vm:AboutWindowViewModel"
|
||||||
Title="About"
|
Title="About"
|
||||||
MaxWidth="300"
|
MaxWidth="300"
|
||||||
MinWidth="300"
|
MinWidth="300"
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<Window xmlns="https://github.com/avaloniaui"
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:vm="using:BetterRaid.ViewModels"
|
xmlns:vm="using:BetterRaid.ViewModels"
|
||||||
|
xmlns:br="using:BetterRaid"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450"
|
xmlns:ai="using:AsyncImageLoader"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="800"
|
||||||
Width="600"
|
Width="600"
|
||||||
Height="800"
|
Height="800"
|
||||||
x:Class="BetterRaid.Views.MainWindow"
|
x:Class="BetterRaid.Views.MainWindow"
|
||||||
@ -108,17 +110,81 @@
|
|||||||
IsScrollInertiaEnabled="True" />
|
IsScrollInertiaEnabled="True" />
|
||||||
</ScrollViewer.GestureRecognizers>
|
</ScrollViewer.GestureRecognizers>
|
||||||
|
|
||||||
<Grid HorizontalAlignment="Stretch"
|
<ListBox ItemsSource="{Binding Channels}">
|
||||||
VerticalAlignment="Stretch"
|
<ListBox.ItemTemplate>
|
||||||
x:Name="raidGrid">
|
<DataTemplate>
|
||||||
|
<Grid ColumnDefinitions="200,*"
|
||||||
|
RowDefinitions="200">
|
||||||
|
|
||||||
|
<ai:AdvancedImage Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Source="{Binding ThumbnailUrl, TargetNullValue={x:Static br:App.ChannelPlaceholderImageUrl}}" />
|
||||||
|
|
||||||
|
<Border Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Height="20"
|
||||||
|
MinWidth="20"
|
||||||
|
CornerRadius="10"
|
||||||
|
Background="#FFFFFF"
|
||||||
|
Padding="3"
|
||||||
|
Margin="0, 0, 10, 10">
|
||||||
|
<TextBlock Text="{Binding ViewerCount, TargetNullValue='-'}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1"
|
||||||
|
Grid.Row="0"
|
||||||
|
ColumnDefinitions="30*, 70*"
|
||||||
|
RowDefinitions="40, 40, 40, 40, 40">
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
FontWeight="Bold"
|
||||||
|
TextDecorations="Underline"
|
||||||
|
Text="{Binding DisplayName, TargetNullValue='???'}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
Text="Category:"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Grid.Row="2"
|
||||||
|
Text="Title:"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Grid.Row="3"
|
||||||
|
Text="Last Raided:"
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="0"
|
||||||
|
Grid.Row="4"
|
||||||
|
Text=""
|
||||||
|
FontWeight="SemiBold" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
Text="{Binding Category, TargetNullValue='-'}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="2"
|
||||||
|
Text="{Binding Title, TargetNullValue='-'}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="3"
|
||||||
|
Text="{Binding LastRaided, TargetNullValue='Never Raided'}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Grid.Row="4"
|
||||||
|
Text="" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -15,279 +15,8 @@ namespace BetterRaid.Views;
|
|||||||
|
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private ObservableCollection<RaidButtonViewModel> _raidButtonVMs;
|
|
||||||
private RaidButtonViewModel? _znButtonVm;
|
|
||||||
private BackgroundWorker _autoUpdater;
|
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
_raidButtonVMs = [];
|
|
||||||
_znButtonVm = null;
|
|
||||||
_autoUpdater = new();
|
|
||||||
|
|
||||||
DataContextChanged += OnDataContextChanged;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_autoUpdater.WorkerSupportsCancellation = true;
|
|
||||||
_autoUpdater.DoWork += UpdateAllTiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDatabaseChanged(object? sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
// TODO: Only if new channel was added or existing were removed
|
|
||||||
// InitializeRaidChannels();
|
|
||||||
GenerateRaidGrid();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDataContextChanged(object? sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (DataContext is MainWindowViewModel vm)
|
|
||||||
{
|
|
||||||
var dbPath = Path.Combine(App.BetterRaidDataPath, "db.json");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
vm.Database = BetterRaidDatabase.LoadFromFile(dbPath);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
var db = new BetterRaidDatabase();
|
|
||||||
db.Save(dbPath);
|
|
||||||
|
|
||||||
vm.Database = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.Database.AutoSave = true;
|
|
||||||
vm.Database.PropertyChanged += OnDatabaseChanged;
|
|
||||||
|
|
||||||
vm.PropertyChanged += OnViewModelChanged;
|
|
||||||
|
|
||||||
InitializeRaidChannels();
|
|
||||||
GenerateRaidGrid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnViewModelChanged(object? sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == nameof(MainWindowViewModel.Filter))
|
|
||||||
{
|
|
||||||
GenerateRaidGrid();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.PropertyName == nameof(MainWindowViewModel.IsLoggedIn) && DataContext is MainWindowViewModel { IsLoggedIn: true })
|
|
||||||
{
|
|
||||||
InitializeRaidChannels();
|
|
||||||
GenerateRaidGrid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeRaidChannels()
|
|
||||||
{
|
|
||||||
if (DataContext is MainWindowViewModel { IsLoggedIn: false })
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_autoUpdater?.IsBusy == false)
|
|
||||||
{
|
|
||||||
_autoUpdater?.CancelAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
_raidButtonVMs.Clear();
|
|
||||||
|
|
||||||
var vm = DataContext as MainWindowViewModel;
|
|
||||||
|
|
||||||
if (vm?.Database == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var channel in vm.Database.Channels)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(channel))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var rbvm = new RaidButtonViewModel(channel)
|
|
||||||
{
|
|
||||||
MainVm = vm
|
|
||||||
};
|
|
||||||
|
|
||||||
_raidButtonVMs.Add(rbvm);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (App.HasUserZnSubbed)
|
|
||||||
{
|
|
||||||
_znButtonVm = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_znButtonVm = new RaidButtonViewModel("zionnetworks")
|
|
||||||
{
|
|
||||||
MainVm = vm,
|
|
||||||
HideDeleteButton = true,
|
|
||||||
IsAd = true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_autoUpdater?.IsBusy == false)
|
|
||||||
{
|
|
||||||
_autoUpdater?.RunWorkerAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateRaidGrid()
|
|
||||||
{
|
|
||||||
if (DataContext is MainWindowViewModel { IsLoggedIn: false })
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var child in raidGrid.Children)
|
|
||||||
{
|
|
||||||
if (child is Button btn)
|
|
||||||
{
|
|
||||||
btn.Click -= OnAddChannelButtonClicked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
raidGrid.Children.Clear();
|
|
||||||
|
|
||||||
var vm = DataContext as MainWindowViewModel;
|
|
||||||
|
|
||||||
if (vm?.Database == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var visibleChannels = _raidButtonVMs.Where(channel =>
|
|
||||||
{
|
|
||||||
var visible = true;
|
|
||||||
if (string.IsNullOrWhiteSpace(vm.Filter) == false)
|
|
||||||
{
|
|
||||||
if (channel.ChannelName.Contains(vm.Filter, StringComparison.OrdinalIgnoreCase) == false)
|
|
||||||
{
|
|
||||||
visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm.Database.OnlyOnline && channel.Channel?.IsLive == false)
|
|
||||||
{
|
|
||||||
visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return visible;
|
|
||||||
}).OrderByDescending(c => c.Channel?.IsLive).ToList();
|
|
||||||
|
|
||||||
var rows = (int)Math.Ceiling((visibleChannels.Count + (App.HasUserZnSubbed ? 1 : 2)) / 3.0);
|
|
||||||
|
|
||||||
for (var i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
raidGrid.RowDefinitions.Add(new RowDefinition(GridLength.Parse("Auto")));
|
|
||||||
}
|
|
||||||
|
|
||||||
var colIndex = App.HasUserZnSubbed ? 0 : 1;
|
|
||||||
var rowIndex = 0;
|
|
||||||
foreach (var channel in visibleChannels)
|
|
||||||
{
|
|
||||||
var btn = new RaidButton
|
|
||||||
{
|
|
||||||
DataContext = channel
|
|
||||||
};
|
|
||||||
|
|
||||||
Grid.SetColumn(btn, colIndex);
|
|
||||||
Grid.SetRow(btn, rowIndex);
|
|
||||||
|
|
||||||
raidGrid.Children.Add(btn);
|
|
||||||
|
|
||||||
colIndex++;
|
|
||||||
if (colIndex % 3 == 0)
|
|
||||||
{
|
|
||||||
colIndex = 0;
|
|
||||||
rowIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var addButton = new Button
|
|
||||||
{
|
|
||||||
Content = "+",
|
|
||||||
FontSize = 72,
|
|
||||||
Margin = new Avalonia.Thickness(5),
|
|
||||||
MinHeight = 250,
|
|
||||||
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch,
|
|
||||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch,
|
|
||||||
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
|
||||||
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center
|
|
||||||
};
|
|
||||||
|
|
||||||
addButton.Click += OnAddChannelButtonClicked;
|
|
||||||
|
|
||||||
Grid.SetColumn(addButton, colIndex);
|
|
||||||
Grid.SetRow(addButton, rowIndex);
|
|
||||||
|
|
||||||
raidGrid.Children.Add(addButton);
|
|
||||||
|
|
||||||
if (App.HasUserZnSubbed == false)
|
|
||||||
{
|
|
||||||
var znButton = new RaidButton
|
|
||||||
{
|
|
||||||
DataContext = _znButtonVm
|
|
||||||
};
|
|
||||||
|
|
||||||
Grid.SetColumn(znButton, 0);
|
|
||||||
Grid.SetRow(znButton, 0);
|
|
||||||
raidGrid.Children.Add(znButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAddChannelButtonClicked(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var dialog = new AddChannelWindow();
|
|
||||||
dialog.CenterToOwner();
|
|
||||||
|
|
||||||
var vm = DataContext as MainWindowViewModel;
|
|
||||||
|
|
||||||
if (vm?.Database == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO Button Command not working, Button remains disabled
|
|
||||||
// This is a dirty workaround
|
|
||||||
dialog.okBtn.Click += (sender, args) => {
|
|
||||||
if (string.IsNullOrWhiteSpace(dialog?.channelNameTxt.Text) == false)
|
|
||||||
{
|
|
||||||
vm.Database.AddChannel(dialog.channelNameTxt.Text);
|
|
||||||
vm.Database.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog?.Close();
|
|
||||||
|
|
||||||
InitializeRaidChannels();
|
|
||||||
GenerateRaidGrid();
|
|
||||||
};
|
|
||||||
|
|
||||||
dialog.ShowDialog(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateChannelData()
|
|
||||||
{
|
|
||||||
var loggedIn = Dispatcher.UIThread.Invoke(() => {
|
|
||||||
return (DataContext as MainWindowViewModel)?.IsLoggedIn ?? false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (loggedIn == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var vm in _raidButtonVMs)
|
|
||||||
{
|
|
||||||
Task.Run(vm.GetOrUpdateChannelAsync);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_znButtonVm != null)
|
|
||||||
{
|
|
||||||
Task.Run(_znButtonVm.GetOrUpdateChannelAsync);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAllTiles(object? sender, DoWorkEventArgs e)
|
|
||||||
{
|
|
||||||
while (e.Cancel == false)
|
|
||||||
{
|
|
||||||
UpdateChannelData();
|
|
||||||
Task.Delay(App.AutoUpdateDelay).Wait();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user