diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..a4713c5
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "csharpier": {
+ "version": "0.27.3",
+ "commands": [
+ "dotnet-csharpier"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..9f6abec
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,91 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+ schedule:
+ - cron: '27 4 * * 1'
+
+jobs:
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners (GitHub.com only)
+ # Consider using larger runners or machines with greater resources for possible analysis time improvements.
+ runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
+ timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
+ permissions:
+ # required for all workflows
+ security-events: write
+
+ # only required for workflows in private repositories
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - language: csharp
+ build-mode: autobuild
+ # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
+ # Use `c-cpp` to analyze code written in C, C++ or both
+ # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
+ # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
+ # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
+ # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ build-mode: ${{ matrix.build-mode }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+
+ # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+ # queries: security-extended,security-and-quality
+
+ # If the analyze step fails for one of the languages you are analyzing with
+ # "We were unable to automatically build your code", modify the matrix above
+ # to set the build mode to "manual" for that language. Then modify this step
+ # to build your code.
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
+ #- if: matrix.build-mode == 'manual'
+ # run: |
+ # echo 'If you are using a "manual" build mode for one or more of the' \
+ # 'languages you are analyzing, replace this with the commands to build' \
+ # 'your code, for example:'
+ # echo ' make bootstrap'
+ # echo ' make release'
+ # exit 1
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/publish-windows.yml b/.github/workflows/publish-windows.yml
index 706be48..9262d16 100644
--- a/.github/workflows/publish-windows.yml
+++ b/.github/workflows/publish-windows.yml
@@ -67,7 +67,9 @@ jobs:
uses: actions/checkout@v3
with:
fetch-depth: 0
-
+ - uses: dotnet/nbgv@master
+ with:
+ setAllVars: true
# Install the .NET Core workload
- name: Install .NET Core
uses: actions/setup-dotnet@v3
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..6cd137c
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "[csharp]": {
+ "editor.defaultFormatter": "csharpier.csharpier-vscode"
+ }
+}
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..2456241
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,19 @@
+
+
+ latest
+ enable
+ true
+ latest
+ strict
+ false
+
+ https://github.com/ArcadeArchie/ArcadePointsBot
+ git
+ ArcadeArchie
+ Copyright 2024 ArcadeArchie
+
+
+
+ 8.0.0
+
+
\ No newline at end of file
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 0000000..b5bbc34
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,60 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
+
\ No newline at end of file
diff --git a/src/ArcadePointsBot/Application/Rewards/DisableRewardsCommandHandler.cs b/src/ArcadePointsBot/Application/Rewards/DisableRewardsCommandHandler.cs
index bc53fb1..de18552 100644
--- a/src/ArcadePointsBot/Application/Rewards/DisableRewardsCommandHandler.cs
+++ b/src/ArcadePointsBot/Application/Rewards/DisableRewardsCommandHandler.cs
@@ -41,7 +41,8 @@ CancellationToken cancellationToken
{
x.IsEnabled = false;
return x;
- }).ToList();
+ })
+ .ToList();
await _rewardService.BulkUpdateRewards(
toDisable,
u => u.SetProperty(p => p.IsEnabled, false)
diff --git a/src/ArcadePointsBot/ArcadePointsBot.csproj b/src/ArcadePointsBot/ArcadePointsBot.csproj
index abae410..e827e5f 100644
--- a/src/ArcadePointsBot/ArcadePointsBot.csproj
+++ b/src/ArcadePointsBot/ArcadePointsBot.csproj
@@ -2,7 +2,6 @@
Exe
net8.0
- enable
true
app.manifest
true
@@ -16,40 +15,38 @@
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers
-
+
diff --git a/src/ArcadePointsBot/Common/Abstractions/Messaging.cs b/src/ArcadePointsBot/Common/Abstractions/Messaging.cs
index 0a72227..f443ec1 100644
--- a/src/ArcadePointsBot/Common/Abstractions/Messaging.cs
+++ b/src/ArcadePointsBot/Common/Abstractions/Messaging.cs
@@ -4,6 +4,7 @@ namespace ArcadePointsBot.Common.Abstractions.Messaging;
internal interface ICommand : Mediator.ICommand
where TResponse : Result;
+
internal interface IQuery : Mediator.IQuery
where TResponse : Result;
@@ -21,6 +22,7 @@ internal interface IQueryHandler : Mediator.IQueryHandler<
///
/// The query type.
/// The query response type.
-internal interface ICommandHandler : Mediator.ICommandHandler
+internal interface ICommandHandler
+ : Mediator.ICommandHandler
where TCommand : ICommand
- where TResponse : Result;
\ No newline at end of file
+ where TResponse : Result;
diff --git a/src/ArcadePointsBot/Common/Errors/TwitchAPI.cs b/src/ArcadePointsBot/Common/Errors/TwitchAPI.cs
index d52ee8b..9197188 100644
--- a/src/ArcadePointsBot/Common/Errors/TwitchAPI.cs
+++ b/src/ArcadePointsBot/Common/Errors/TwitchAPI.cs
@@ -4,20 +4,25 @@ namespace ArcadePointsBot.Errors
{
public static class TwitchAPI
{
- public static Error BadCredentials => new(
- "TTV.API.BadCreds",
- "The Credentials are invalid, resetting them and restarting the bot is recommended");
- public static Error BadRewardTitle => new(
- "TTV.API.BadTitle",
- "The Reward Title was disallowed by twitch, try a differend one");
- public static Error DupeRewardTitle => new(
- "TTV.API.DupeTitle",
- "The Reward with this title already exists, try a differend one or delete the duplicate");
+ public static Error BadCredentials =>
+ new(
+ "TTV.API.BadCreds",
+ "The Credentials are invalid, resetting them and restarting the bot is recommended"
+ );
+ public static Error BadRewardTitle =>
+ new(
+ "TTV.API.BadTitle",
+ "The Reward Title was disallowed by twitch, try a differend one"
+ );
+ public static Error DupeRewardTitle =>
+ new(
+ "TTV.API.DupeTitle",
+ "The Reward with this title already exists, try a differend one or delete the duplicate"
+ );
}
+
public static class Database
{
- public static Error NotFound => new(
- "DB.404",
- "Entry not found in the database");
+ public static Error NotFound => new("DB.404", "Entry not found in the database");
}
}
diff --git a/src/ArcadePointsBot/Common/Primitives/Result/Result.cs b/src/ArcadePointsBot/Common/Primitives/Result/Result.cs
index 65a5774..cd77ea3 100644
--- a/src/ArcadePointsBot/Common/Primitives/Result/Result.cs
+++ b/src/ArcadePointsBot/Common/Primitives/Result/Result.cs
@@ -65,8 +65,7 @@ protected Result(bool isSuccess, Error error)
/// The error in case the value is null.
/// A new instance of with the specified value or an error.
public static Result Create(TValue? value, Error error)
- where TValue : class
- => value is null ? Failure(error) : Success(value);
+ where TValue : class => value is null ? Failure(error) : Success(value);
///
/// Returns a failure with the specified error.
@@ -107,4 +106,4 @@ public static Result FirstFailureOrSuccess(params Result[] results)
return Success();
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Common/Primitives/Result/ResultExtensions.cs b/src/ArcadePointsBot/Common/Primitives/Result/ResultExtensions.cs
index 377e25d..1dba4cb 100644
--- a/src/ArcadePointsBot/Common/Primitives/Result/ResultExtensions.cs
+++ b/src/ArcadePointsBot/Common/Primitives/Result/ResultExtensions.cs
@@ -53,8 +53,10 @@ public static Result Map(this Result result, Func
/// The success result with the bound value if the current result is a success result, otherwise a failure result.
///
- public static async Task Bind(this Result result, Func> func) =>
- result.IsSuccess ? await func(result.Value) : Result.Failure(result.Error);
+ public static async Task Bind(
+ this Result result,
+ Func> func
+ ) => result.IsSuccess ? await func(result.Value) : Result.Failure(result.Error);
///
/// Binds to the result of the function and returns it.
@@ -66,8 +68,10 @@ public static async Task Bind(this Result result, Func
/// The success result with the bound value if the current result is a success result, otherwise a failure result.
///
- public static async Task> Bind(this Result result, Func>> func) =>
- result.IsSuccess ? await func(result.Value) : Result.Failure(result.Error);
+ public static async Task> Bind(
+ this Result result,
+ Func>> func
+ ) => result.IsSuccess ? await func(result.Value) : Result.Failure(result.Error);
///
/// Matches the success status of the result to the corresponding functions.
@@ -79,7 +83,11 @@ public static async Task> Bind(this Result result,
///
/// The result of the on-success function if the result is a success result, otherwise the result of the failure result.
///
- public static async Task Match(this Task resultTask, Func onSuccess, Func onFailure)
+ public static async Task Match(
+ this Task resultTask,
+ Func onSuccess,
+ Func onFailure
+ )
{
Result result = await resultTask;
@@ -100,7 +108,8 @@ public static async Task Match(this Task resultTask, Func onSuc
public static async Task Match(
this Task> resultTask,
Func onSuccess,
- Func onFailure)
+ Func onFailure
+ )
{
Result result = await resultTask;
diff --git a/src/ArcadePointsBot/Common/Primitives/Result/ResultT.cs b/src/ArcadePointsBot/Common/Primitives/Result/ResultT.cs
index 71a3e55..0d89427 100644
--- a/src/ArcadePointsBot/Common/Primitives/Result/ResultT.cs
+++ b/src/ArcadePointsBot/Common/Primitives/Result/ResultT.cs
@@ -21,17 +21,19 @@ public class Result : Result
/// The flag indicating if the result is successful.
/// The error.
protected internal Result(TValue? value, bool isSuccess, Error error)
- : base(isSuccess, error)
- => _value = value;
+ : base(isSuccess, error) => _value = value;
///
/// Gets the result value if the result is successful, otherwise throws an exception.
///
/// The result value if the result is successful.
/// when is true.
- public TValue Value => IsSuccess
- ? _value!
- : throw new InvalidOperationException("The value of a failure result can not be accessed.");
+ public TValue Value =>
+ IsSuccess
+ ? _value!
+ : throw new InvalidOperationException(
+ "The value of a failure result can not be accessed."
+ );
public static implicit operator Result(TValue value) => Success(value);
}
diff --git a/src/ArcadePointsBot/Common/Primitives/ServiceLifetimes.cs b/src/ArcadePointsBot/Common/Primitives/ServiceLifetimes.cs
index 7aad7bc..5777937 100644
--- a/src/ArcadePointsBot/Common/Primitives/ServiceLifetimes.cs
+++ b/src/ArcadePointsBot/Common/Primitives/ServiceLifetimes.cs
@@ -14,4 +14,4 @@ public interface ITransient;
///
/// Represents the scoped service lifetime.
///
-public interface IScoped;
\ No newline at end of file
+public interface IScoped;
diff --git a/src/ArcadePointsBot/Data/Abstractions/IUnitOfWork.cs b/src/ArcadePointsBot/Data/Abstractions/IUnitOfWork.cs
index a9fd275..ff41475 100644
--- a/src/ArcadePointsBot/Data/Abstractions/IUnitOfWork.cs
+++ b/src/ArcadePointsBot/Data/Abstractions/IUnitOfWork.cs
@@ -1,25 +1,28 @@
-using Microsoft.EntityFrameworkCore.Storage;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore.Storage;
namespace ArcadePointsBot.Data.Abstractions
{
public interface IUnitOfWork
{
- Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
+ Task SaveChangesAsync(
+ CancellationToken cancellationToken = default(CancellationToken)
+ );
- Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default);
+ Task SaveChangesAsync(
+ bool acceptAllChangesOnSuccess,
+ CancellationToken cancellationToken = default
+ );
int SaveChanges();
int SaveChanges(bool acceptAllChangesOnSuccess);
-
-
IDbContextTransaction BeginTransaction();
Task BeginTransactionAsync();
void CommitTransaction();
diff --git a/src/ArcadePointsBot/Data/Abstractions/Repositories/IRepository.cs b/src/ArcadePointsBot/Data/Abstractions/Repositories/IRepository.cs
index 4cc2ffe..b53dd93 100644
--- a/src/ArcadePointsBot/Data/Abstractions/Repositories/IRepository.cs
+++ b/src/ArcadePointsBot/Data/Abstractions/Repositories/IRepository.cs
@@ -1,15 +1,16 @@
-using ArcadePointsBot.Domain;
-using Microsoft.EntityFrameworkCore.Query;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
+using ArcadePointsBot.Domain;
+using Microsoft.EntityFrameworkCore.Query;
namespace ArcadePointsBot.Data.Abstractions.Repositories;
-public interface IEntityRepository : IReadRepository, IWriteRepository where T : IEntity
+public interface IEntityRepository : IReadRepository, IWriteRepository
+ where T : IEntity
{
///
/// Finds an entity from data store.
@@ -26,12 +27,14 @@ public interface IEntityRepository : IReadRepository, IWriteRepositor
Task FindAsync(TId id);
}
-public interface IRepository where T : IEntity
+public interface IRepository
+ where T : IEntity
{
IUnitOfWork UnitOfWork { get; }
}
-public interface IWriteRepository : IRepository where T : IEntity
+public interface IWriteRepository : IRepository
+ where T : IEntity
{
///
/// Adds the entity to the data store
@@ -82,7 +85,10 @@ public interface IWriteRepository : IRepository where T : IEntit
/// The collection of entities to update
void UpdateRange(IEnumerable entities);
- public Task ExecuteUpdate(IEnumerable entities, Expression, SetPropertyCalls>> setPropertyCalls);
+ public Task ExecuteUpdate(
+ IEnumerable entities,
+ Expression, SetPropertyCalls>> setPropertyCalls
+ );
}
///
@@ -112,7 +118,7 @@ public interface IReadRepository
IQueryable GetAll();
///
- /// Retrieves all entities that satisfy the given condition from the data store as
+ /// Retrieves all entities that satisfy the given condition from the data store as
///
/// Condition
/// Query
@@ -144,4 +150,4 @@ public interface IReadRepository
/// Condition
/// Entity
Task GetSingleAsync(Expression> predicate);
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Data/Contexts/ApplicationDbContext.cs b/src/ArcadePointsBot/Data/Contexts/ApplicationDbContext.cs
index fdfa018..465d1bb 100644
--- a/src/ArcadePointsBot/Data/Contexts/ApplicationDbContext.cs
+++ b/src/ArcadePointsBot/Data/Contexts/ApplicationDbContext.cs
@@ -1,13 +1,13 @@
-using ArcadePointsBot.Data.Abstractions;
-using ArcadePointsBot.Domain.Rewards;
-using ArcadePointsBot.ViewModels;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Storage;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using ArcadePointsBot.Data.Abstractions;
+using ArcadePointsBot.Domain.Rewards;
+using ArcadePointsBot.ViewModels;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Storage;
namespace ArcadePointsBot.Data.Contexts;
@@ -15,10 +15,9 @@ public class ApplicationDbContext : DbContext, IUnitOfWork
{
public DbSet Rewards { get; set; }
public DbSet Actions { get; set; }
- public ApplicationDbContext(DbContextOptions options) : base(options)
- {
-
- }
+
+ public ApplicationDbContext(DbContextOptions options)
+ : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -27,7 +26,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
}
public IDbContextTransaction BeginTransaction() => Database.BeginTransaction();
+
public Task BeginTransactionAsync() => Database.BeginTransactionAsync();
+
public void CommitTransaction() => Database.CommitTransaction();
+
public Task CommitTransactionAsync() => Database.CommitTransactionAsync();
}
diff --git a/src/ArcadePointsBot/Data/Migrations/20231022033828_InitialCreate.cs b/src/ArcadePointsBot/Data/Migrations/20231022033828_InitialCreate.cs
index 4506458..2d7c71a 100644
--- a/src/ArcadePointsBot/Data/Migrations/20231022033828_InitialCreate.cs
+++ b/src/ArcadePointsBot/Data/Migrations/20231022033828_InitialCreate.cs
@@ -10,64 +10,71 @@ public partial class InitialCreate : Migration
///
protected override void Up(MigrationBuilder migrationBuilder)
{
- migrationBuilder.AlterDatabase()
- .Annotation("MySql:CharSet", "utf8mb4");
+ migrationBuilder.AlterDatabase().Annotation("MySql:CharSet", "utf8mb4");
- migrationBuilder.CreateTable(
- name: "Rewards",
- columns: table => new
- {
- Id = table.Column(type: "varchar(255)", nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- Title = table.Column(type: "longtext", nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- Cost = table.Column(type: "int", nullable: false),
- RequireInput = table.Column(type: "tinyint(1)", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Rewards", x => x.Id);
- })
+ migrationBuilder
+ .CreateTable(
+ name: "Rewards",
+ columns: table => new
+ {
+ Id = table
+ .Column(type: "varchar(255)", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Title = table
+ .Column(type: "longtext", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Cost = table.Column(type: "int", nullable: false),
+ RequireInput = table.Column(type: "tinyint(1)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Rewards", x => x.Id);
+ }
+ )
.Annotation("MySql:CharSet", "utf8mb4");
- migrationBuilder.CreateTable(
- name: "Actions",
- columns: table => new
- {
- Id = table.Column(type: "varchar(255)", nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- RewardId = table.Column(type: "varchar(255)", nullable: false)
- .Annotation("MySql:CharSet", "utf8mb4"),
- Duration = table.Column(type: "int", nullable: true),
- ActionType = table.Column(type: "int", nullable: false),
- ActionKey = table.Column(type: "int", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Actions", x => x.Id);
- table.ForeignKey(
- name: "FK_Actions_Rewards_RewardId",
- column: x => x.RewardId,
- principalTable: "Rewards",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- })
+ migrationBuilder
+ .CreateTable(
+ name: "Actions",
+ columns: table => new
+ {
+ Id = table
+ .Column(type: "varchar(255)", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ RewardId = table
+ .Column(type: "varchar(255)", nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Duration = table.Column(type: "int", nullable: true),
+ ActionType = table.Column(type: "int", nullable: false),
+ ActionKey = table.Column(type: "int", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_Actions", x => x.Id);
+ table.ForeignKey(
+ name: "FK_Actions_Rewards_RewardId",
+ column: x => x.RewardId,
+ principalTable: "Rewards",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade
+ );
+ }
+ )
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Actions_RewardId",
table: "Actions",
- column: "RewardId");
+ column: "RewardId"
+ );
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
- migrationBuilder.DropTable(
- name: "Actions");
+ migrationBuilder.DropTable(name: "Actions");
- migrationBuilder.DropTable(
- name: "Rewards");
+ migrationBuilder.DropTable(name: "Rewards");
}
}
}
diff --git a/src/ArcadePointsBot/Data/Migrations/20231024011504_AddIndexCol.cs b/src/ArcadePointsBot/Data/Migrations/20231024011504_AddIndexCol.cs
index d758ea3..8ba66d3 100644
--- a/src/ArcadePointsBot/Data/Migrations/20231024011504_AddIndexCol.cs
+++ b/src/ArcadePointsBot/Data/Migrations/20231024011504_AddIndexCol.cs
@@ -15,15 +15,14 @@ protected override void Up(MigrationBuilder migrationBuilder)
table: "Actions",
type: "int",
nullable: false,
- defaultValue: 0);
+ defaultValue: 0
+ );
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
- migrationBuilder.DropColumn(
- name: "Index",
- table: "Actions");
+ migrationBuilder.DropColumn(name: "Index", table: "Actions");
}
}
}
diff --git a/src/ArcadePointsBot/Data/Migrations/20231024013830_AddEnabledCol.cs b/src/ArcadePointsBot/Data/Migrations/20231024013830_AddEnabledCol.cs
index 4981ea0..3ad9e7a 100644
--- a/src/ArcadePointsBot/Data/Migrations/20231024013830_AddEnabledCol.cs
+++ b/src/ArcadePointsBot/Data/Migrations/20231024013830_AddEnabledCol.cs
@@ -15,15 +15,14 @@ protected override void Up(MigrationBuilder migrationBuilder)
table: "Rewards",
type: "tinyint(1)",
nullable: false,
- defaultValue: false);
+ defaultValue: false
+ );
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
- migrationBuilder.DropColumn(
- name: "IsEnabled",
- table: "Rewards");
+ migrationBuilder.DropColumn(name: "IsEnabled", table: "Rewards");
}
}
}
diff --git a/src/ArcadePointsBot/Data/Migrations/20231031040438_NewActionType.cs b/src/ArcadePointsBot/Data/Migrations/20231031040438_NewActionType.cs
index 5b4333b..c0dff2c 100644
--- a/src/ArcadePointsBot/Data/Migrations/20231031040438_NewActionType.cs
+++ b/src/ArcadePointsBot/Data/Migrations/20231031040438_NewActionType.cs
@@ -16,7 +16,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "TEXT",
nullable: false,
oldClrType: typeof(string),
- oldType: "longtext");
+ oldType: "longtext"
+ );
migrationBuilder.AlterColumn(
name: "RequireInput",
@@ -24,7 +25,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(bool),
- oldType: "tinyint(1)");
+ oldType: "tinyint(1)"
+ );
migrationBuilder.AlterColumn(
name: "IsEnabled",
@@ -32,7 +34,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(bool),
- oldType: "tinyint(1)");
+ oldType: "tinyint(1)"
+ );
migrationBuilder.AlterColumn(
name: "Cost",
@@ -40,7 +43,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(int),
- oldType: "int");
+ oldType: "int"
+ );
migrationBuilder.AlterColumn(
name: "Id",
@@ -48,7 +52,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "TEXT",
nullable: false,
oldClrType: typeof(string),
- oldType: "varchar(255)");
+ oldType: "varchar(255)"
+ );
migrationBuilder.AlterColumn(
name: "RewardId",
@@ -56,7 +61,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "TEXT",
nullable: false,
oldClrType: typeof(string),
- oldType: "varchar(255)");
+ oldType: "varchar(255)"
+ );
migrationBuilder.AlterColumn(
name: "Index",
@@ -64,7 +70,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(int),
- oldType: "int");
+ oldType: "int"
+ );
migrationBuilder.AlterColumn(
name: "Duration",
@@ -73,7 +80,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
nullable: true,
oldClrType: typeof(int),
oldType: "int",
- oldNullable: true);
+ oldNullable: true
+ );
migrationBuilder.AlterColumn(
name: "ActionType",
@@ -81,7 +89,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(int),
- oldType: "int");
+ oldType: "int"
+ );
migrationBuilder.AlterColumn(
name: "ActionKey",
@@ -89,7 +98,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "INTEGER",
nullable: false,
oldClrType: typeof(int),
- oldType: "int");
+ oldType: "int"
+ );
migrationBuilder.AlterColumn(
name: "Id",
@@ -97,7 +107,8 @@ protected override void Up(MigrationBuilder migrationBuilder)
type: "TEXT",
nullable: false,
oldClrType: typeof(string),
- oldType: "varchar(255)");
+ oldType: "varchar(255)"
+ );
migrationBuilder.CreateTable(
name: "MouseRewardAction",
@@ -118,20 +129,22 @@ protected override void Up(MigrationBuilder migrationBuilder)
column: x => x.RewardId,
principalTable: "Rewards",
principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- });
+ onDelete: ReferentialAction.Cascade
+ );
+ }
+ );
migrationBuilder.CreateIndex(
name: "IX_MouseRewardAction_RewardId",
table: "MouseRewardAction",
- column: "RewardId");
+ column: "RewardId"
+ );
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
- migrationBuilder.DropTable(
- name: "MouseRewardAction");
+ migrationBuilder.DropTable(name: "MouseRewardAction");
migrationBuilder.AlterColumn(
name: "Title",
@@ -139,7 +152,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "longtext",
nullable: false,
oldClrType: typeof(string),
- oldType: "TEXT");
+ oldType: "TEXT"
+ );
migrationBuilder.AlterColumn(
name: "RequireInput",
@@ -147,7 +161,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "tinyint(1)",
nullable: false,
oldClrType: typeof(bool),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "IsEnabled",
@@ -155,7 +170,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "tinyint(1)",
nullable: false,
oldClrType: typeof(bool),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "Cost",
@@ -163,7 +179,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "int",
nullable: false,
oldClrType: typeof(int),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "Id",
@@ -171,7 +188,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "varchar(255)",
nullable: false,
oldClrType: typeof(string),
- oldType: "TEXT");
+ oldType: "TEXT"
+ );
migrationBuilder.AlterColumn(
name: "RewardId",
@@ -179,7 +197,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "varchar(255)",
nullable: false,
oldClrType: typeof(string),
- oldType: "TEXT");
+ oldType: "TEXT"
+ );
migrationBuilder.AlterColumn(
name: "Index",
@@ -187,7 +206,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "int",
nullable: false,
oldClrType: typeof(int),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "Duration",
@@ -196,7 +216,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
nullable: true,
oldClrType: typeof(int),
oldType: "INTEGER",
- oldNullable: true);
+ oldNullable: true
+ );
migrationBuilder.AlterColumn(
name: "ActionType",
@@ -204,7 +225,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "int",
nullable: false,
oldClrType: typeof(int),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "ActionKey",
@@ -212,7 +234,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "int",
nullable: false,
oldClrType: typeof(int),
- oldType: "INTEGER");
+ oldType: "INTEGER"
+ );
migrationBuilder.AlterColumn(
name: "Id",
@@ -220,7 +243,8 @@ protected override void Down(MigrationBuilder migrationBuilder)
type: "varchar(255)",
nullable: false,
oldClrType: typeof(string),
- oldType: "TEXT");
+ oldType: "TEXT"
+ );
}
}
}
diff --git a/src/ArcadePointsBot/Data/Migrations/20231101142744_RewardCategory.cs b/src/ArcadePointsBot/Data/Migrations/20231101142744_RewardCategory.cs
index ef4b8ce..6caa796 100644
--- a/src/ArcadePointsBot/Data/Migrations/20231101142744_RewardCategory.cs
+++ b/src/ArcadePointsBot/Data/Migrations/20231101142744_RewardCategory.cs
@@ -14,15 +14,14 @@ protected override void Up(MigrationBuilder migrationBuilder)
name: "Category",
table: "Rewards",
type: "TEXT",
- nullable: true);
+ nullable: true
+ );
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
- migrationBuilder.DropColumn(
- name: "Category",
- table: "Rewards");
+ migrationBuilder.DropColumn(name: "Category", table: "Rewards");
}
}
}
diff --git a/src/ArcadePointsBot/Data/Repositories/DataEntityRepository.cs b/src/ArcadePointsBot/Data/Repositories/DataEntityRepository.cs
index f958ca2..ce03d83 100644
--- a/src/ArcadePointsBot/Data/Repositories/DataEntityRepository.cs
+++ b/src/ArcadePointsBot/Data/Repositories/DataEntityRepository.cs
@@ -1,20 +1,21 @@
-using ArcadePointsBot.Data.Abstractions;
-using ArcadePointsBot.Data.Abstractions.Repositories;
-using ArcadePointsBot.Data.Contexts;
-using ArcadePointsBot.Domain;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Query;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
+using ArcadePointsBot.Data.Abstractions;
+using ArcadePointsBot.Data.Abstractions.Repositories;
+using ArcadePointsBot.Data.Contexts;
+using ArcadePointsBot.Domain;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Query;
using TwitchLib.Api.Helix.Models.Soundtrack;
namespace ArcadePointsBot.Data.Repositories
{
- internal class DataEntityRepository : IEntityRepository where T : class, IEntity
+ internal class DataEntityRepository : IEntityRepository
+ where T : class, IEntity
{
protected readonly DbSet _entities;
protected readonly ApplicationDbContext _context;
@@ -112,8 +113,10 @@ public void UpdateRange(IEnumerable entities)
}
}
- public Task ExecuteUpdate(IEnumerable entities, Expression, SetPropertyCalls>> setPropertyCalls)
- => _entities.Where(x => entities.Contains(x)).ExecuteUpdateAsync(setPropertyCalls);
+ public Task ExecuteUpdate(
+ IEnumerable entities,
+ Expression, SetPropertyCalls>> setPropertyCalls
+ ) => _entities.Where(x => entities.Contains(x)).ExecuteUpdateAsync(setPropertyCalls);
public T? Find(TId id)
{
diff --git a/src/ArcadePointsBot/Data/Repositories/RewardRepository.cs b/src/ArcadePointsBot/Data/Repositories/RewardRepository.cs
index 755db18..1f5f2af 100644
--- a/src/ArcadePointsBot/Data/Repositories/RewardRepository.cs
+++ b/src/ArcadePointsBot/Data/Repositories/RewardRepository.cs
@@ -1,22 +1,26 @@
-using ArcadePointsBot.Data.Contexts;
+using System.Threading.Tasks;
+using ArcadePointsBot.Data.Contexts;
using ArcadePointsBot.Domain.Rewards;
using Microsoft.EntityFrameworkCore;
-using System.Threading.Tasks;
namespace ArcadePointsBot.Data.Repositories
{
internal class RewardRepository : DataEntityRepository, IRewardRepository
{
- public RewardRepository(ApplicationDbContext context) : base(context)
- {
- }
+ public RewardRepository(ApplicationDbContext context)
+ : base(context) { }
-
- public new TwitchReward? Find(string id) {
+ public new TwitchReward? Find(string id)
+ {
return _entities.Find(id);
}
- public new Task FindAsync(string id) {
- return _entities.Include(x => x.KeyboardActions).Include(x => x.MouseActions).FirstOrDefaultAsync(x => x.Id == id);
+
+ public new Task FindAsync(string id)
+ {
+ return _entities
+ .Include(x => x.KeyboardActions)
+ .Include(x => x.MouseActions)
+ .FirstOrDefaultAsync(x => x.Id == id);
}
}
}
diff --git a/src/ArcadePointsBot/Domain/Rewards/IRewardRepository.cs b/src/ArcadePointsBot/Domain/Rewards/IRewardRepository.cs
index c339350..3c8c457 100644
--- a/src/ArcadePointsBot/Domain/Rewards/IRewardRepository.cs
+++ b/src/ArcadePointsBot/Domain/Rewards/IRewardRepository.cs
@@ -2,7 +2,5 @@
namespace ArcadePointsBot.Domain.Rewards
{
- public interface IRewardRepository : IEntityRepository
- {
- }
+ public interface IRewardRepository : IEntityRepository { }
}
diff --git a/src/ArcadePointsBot/Domain/Rewards/KeyboardRewardAction.cs b/src/ArcadePointsBot/Domain/Rewards/KeyboardRewardAction.cs
index fe48bdc..2c59ea9 100644
--- a/src/ArcadePointsBot/Domain/Rewards/KeyboardRewardAction.cs
+++ b/src/ArcadePointsBot/Domain/Rewards/KeyboardRewardAction.cs
@@ -1,18 +1,25 @@
-using Avalonia.Input;
-using ArcadePointsBot.Util;
-using ReactiveUI.Fody.Helpers;
-using ReactiveUI;
-using System;
+using System;
using System.Collections;
+using ArcadePointsBot.Util;
using ArcadePointsBot.ViewModels;
+using Avalonia.Input;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
namespace ArcadePointsBot.Domain.Rewards;
public class KeyboardRewardAction : RewardAction
{
-
public KeyboardRewardAction() { }
- public KeyboardRewardAction(string id, int index, TwitchReward reward, int? duration, KeyboardActionType actionType, Key actionKey)
+
+ public KeyboardRewardAction(
+ string id,
+ int index,
+ TwitchReward reward,
+ int? duration,
+ KeyboardActionType actionType,
+ Key actionKey
+ )
{
Id = id;
Index = index;
@@ -22,10 +29,20 @@ public KeyboardRewardAction(string id, int index, TwitchReward reward, int? dura
ActionKey = actionKey;
}
- public static KeyboardRewardAction FromVMType(TwitchReward reward, RewardActionViewModel actionVM)
+ public static KeyboardRewardAction FromVMType(
+ TwitchReward reward,
+ RewardActionViewModel actionVM
+ )
{
var actionType = (KeyboardActionType)actionVM.ActionKeyType!;
var key = (Key)actionVM.ActionKey!;
- return new(Guid.NewGuid().ToString(), actionVM.Index, reward, actionVM.Duration, actionType, key);
+ return new(
+ Guid.NewGuid().ToString(),
+ actionVM.Index,
+ reward,
+ actionVM.Duration,
+ actionType,
+ key
+ );
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Domain/Rewards/MouseRewardAction.cs b/src/ArcadePointsBot/Domain/Rewards/MouseRewardAction.cs
index 7d56761..a3bac65 100644
--- a/src/ArcadePointsBot/Domain/Rewards/MouseRewardAction.cs
+++ b/src/ArcadePointsBot/Domain/Rewards/MouseRewardAction.cs
@@ -1,13 +1,21 @@
-using Avalonia.Input;
-using System;
+using System;
using ArcadePointsBot.ViewModels;
+using Avalonia.Input;
namespace ArcadePointsBot.Domain.Rewards;
public class MouseRewardAction : RewardAction
{
public MouseRewardAction() { }
- public MouseRewardAction(string id, int index, TwitchReward reward, int? duration, MouseActionType actionType, MouseButton actionKey)
+
+ public MouseRewardAction(
+ string id,
+ int index,
+ TwitchReward reward,
+ int? duration,
+ MouseActionType actionType,
+ MouseButton actionKey
+ )
{
Id = id;
Index = index;
@@ -21,6 +29,13 @@ public static MouseRewardAction FromVMType(TwitchReward reward, RewardActionView
{
var actionType = (MouseActionType)actionVM.ActionKeyType!;
var key = (MouseButton)actionVM.ActionKey!;
- return new(Guid.NewGuid().ToString(), actionVM.Index, reward, actionVM.Duration, actionType, key);
+ return new(
+ Guid.NewGuid().ToString(),
+ actionVM.Index,
+ reward,
+ actionVM.Duration,
+ actionType,
+ key
+ );
}
}
diff --git a/src/ArcadePointsBot/Domain/Rewards/RewardAction.cs b/src/ArcadePointsBot/Domain/Rewards/RewardAction.cs
index ff608a8..f43de5a 100644
--- a/src/ArcadePointsBot/Domain/Rewards/RewardAction.cs
+++ b/src/ArcadePointsBot/Domain/Rewards/RewardAction.cs
@@ -2,6 +2,7 @@
using System.ComponentModel;
namespace ArcadePointsBot.Domain.Rewards;
+
public abstract class RewardAction : IEntity
{
public string Id { get; set; } = null!;
@@ -9,6 +10,7 @@ public abstract class RewardAction : IEntity
public TwitchReward Reward { get; set; } = null!;
public int? Duration { get; set; }
}
+
public abstract class RewardAction : RewardAction
where TType : struct, Enum
where TKey : struct, Enum
@@ -21,6 +23,7 @@ public enum ActionType
{
[Description("ActionType_Keyboard")]
Keyboard,
+
[Description("ActionType_Mouse")]
Mouse
}
@@ -29,19 +32,25 @@ public enum KeyboardActionType
{
[Description("KeyboardActionType_Tap")]
Tap,
+
[Description("KeyboardActionType_Press")]
Press,
+
[Description("KeyboardActionType_Release")]
Release
}
+
public enum MouseActionType
{
[Description("MouseActionType_Click")]
Click,
+
[Description("MouseActionType_DoubleClick")]
DoubleClick,
+
[Description("KeyboardActionType_Press")]
Press,
+
[Description("KeyboardActionType_Release")]
Release
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Domain/Rewards/TwitchReward.cs b/src/ArcadePointsBot/Domain/Rewards/TwitchReward.cs
index a78f321..2630994 100644
--- a/src/ArcadePointsBot/Domain/Rewards/TwitchReward.cs
+++ b/src/ArcadePointsBot/Domain/Rewards/TwitchReward.cs
@@ -15,24 +15,27 @@ public class TwitchReward : IEntity, INotifyPropertyChanged
private bool _isEnabled;
public bool IsEnabled
{
- get => _isEnabled; set
+ get => _isEnabled;
+ set
{
_isEnabled = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEnabled)));
}
}
- public IList KeyboardActions { get; init; } = new List();
+ public IList KeyboardActions { get; init; } =
+ new List();
public IList MouseActions { get; init; } = new List();
public event PropertyChangedEventHandler? PropertyChanged;
- public static TwitchReward FromRemote(CustomReward remoteReward) => new TwitchReward
- {
- Id = remoteReward.Id,
- Title = remoteReward.Title,
- Cost = remoteReward.Cost,
- RequireInput = remoteReward.IsUserInputRequired
- };
+ public static TwitchReward FromRemote(CustomReward remoteReward) =>
+ new TwitchReward
+ {
+ Id = remoteReward.Id,
+ Title = remoteReward.Title,
+ Cost = remoteReward.Cost,
+ RequireInput = remoteReward.IsUserInputRequired
+ };
}
}
diff --git a/src/ArcadePointsBot/Domain/ValueObject.cs b/src/ArcadePointsBot/Domain/ValueObject.cs
index 56d5c65..92b6279 100644
--- a/src/ArcadePointsBot/Domain/ValueObject.cs
+++ b/src/ArcadePointsBot/Domain/ValueObject.cs
@@ -63,7 +63,11 @@ public override bool Equals(object? obj)
///
public override int GetHashCode() =>
- GetAtomicValues().Aggregate(default(int), (hashcode, value) => HashCode.Combine(hashcode, value.GetHashCode()));
+ GetAtomicValues()
+ .Aggregate(
+ default(int),
+ (hashcode, value) => HashCode.Combine(hashcode, value.GetHashCode())
+ );
///
/// Gets the atomic values of the value object.
diff --git a/src/ArcadePointsBot/GlobalRxExceptionHandler.cs b/src/ArcadePointsBot/GlobalRxExceptionHandler.cs
index 084035c..7d60578 100644
--- a/src/ArcadePointsBot/GlobalRxExceptionHandler.cs
+++ b/src/ArcadePointsBot/GlobalRxExceptionHandler.cs
@@ -1,10 +1,10 @@
-using Avalonia.Controls.ApplicationLifetimes;
+using System;
+using System.Diagnostics;
+using System.Reactive.Concurrency;
+using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using Microsoft.Extensions.Logging;
using ReactiveUI;
-using System;
-using System.Diagnostics;
-using System.Reactive.Concurrency;
namespace ArcadePointsBot
{
@@ -19,25 +19,38 @@ public GlobalRxExceptionHandler(ILogger logger)
public void OnCompleted()
{
- if (Debugger.IsAttached) Debugger.Break();
- RxApp.MainThreadScheduler.Schedule(() => { throw new NotImplementedException(); });
+ if (Debugger.IsAttached)
+ Debugger.Break();
+ RxApp.MainThreadScheduler.Schedule(() =>
+ {
+ throw new NotImplementedException();
+ });
}
public void OnError(Exception error)
{
- if (Debugger.IsAttached) Debugger.Break();
+ if (Debugger.IsAttached)
+ Debugger.Break();
_logger.LogCritical(error, "Something went wrong in the UI");
- RxApp.MainThreadScheduler.Schedule(() => { throw error; });
+ RxApp.MainThreadScheduler.Schedule(() =>
+ {
+ throw error;
+ });
}
public void OnNext(Exception value)
{
- if (Debugger.IsAttached) Debugger.Break();
+ if (Debugger.IsAttached)
+ Debugger.Break();
_logger.LogCritical(value, "Something went wrong in the UI");
- if (App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
+ if (
+ App.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime
+ )
Dispatcher.UIThread.Post(() => lifetime.Shutdown(value.HResult));
- RxApp.MainThreadScheduler.Schedule(() => { throw value; });
-
+ RxApp.MainThreadScheduler.Schedule(() =>
+ {
+ throw value;
+ });
}
}
}
diff --git a/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthConfig.cs b/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthConfig.cs
index 9fd439f..cbf92a6 100644
--- a/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthConfig.cs
+++ b/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthConfig.cs
@@ -1,23 +1,24 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using System;
+using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.CompilerServices;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
namespace ArcadePointsBot.Auth;
+
public class TwitchAuthConfig : INotifyPropertyChanged
{
private DateTimeOffset? accessTokenExpiration;
private string? refreshToken;
private string? identityToken;
private string? accessToken;
-
+
[Required]
public string ClientId { get; init; } = string.Empty;
-
+
[Required]
public string ClientSecret { get; init; } = string.Empty;
@@ -70,7 +71,8 @@ public DateTimeOffset? AccessTokenExpiration
private void ParseIdToken()
{
- if (string.IsNullOrEmpty(IdentityToken)) return;
+ if (string.IsNullOrEmpty(IdentityToken))
+ return;
var parts = IdentityToken.Split('.');
byte[]? json = null;
try
@@ -90,20 +92,24 @@ private void ParseIdToken()
#region INotifyPropertyChanged
public event PropertyChangedEventHandler? PropertyChanged;
- protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null, object? value = null)
+ protected virtual void OnPropertyChanged(
+ [CallerMemberName] string? propertyName = null,
+ object? value = null
+ )
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgsEx(propertyName, value));
}
- #endregion
-
+ #endregion
}
+
public class PropertyChangedEventArgsEx : PropertyChangedEventArgs
{
private readonly object? _value;
public virtual object? Value => _value;
- public PropertyChangedEventArgsEx(string? propertyName, object? value) : base(propertyName)
+ public PropertyChangedEventArgsEx(string? propertyName, object? value)
+ : base(propertyName)
{
_value = value;
}
diff --git a/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthenticationService.cs b/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthenticationService.cs
index 43dbfb5..d2b0af8 100644
--- a/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthenticationService.cs
+++ b/src/ArcadePointsBot/Infrastructure/Auth/TwitchAuthenticationService.cs
@@ -1,42 +1,50 @@
-using IdentityModel.OidcClient;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using System;
+using System;
using System.Net.Http;
using System.Threading.Tasks;
+using IdentityModel.OidcClient;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
namespace ArcadePointsBot.Auth
{
internal class TwitchAuthenticationService : IAuthenticationService
{
- private const string SCOPES = "openid channel:read:redemptions user:read:chat user:bot channel:moderate channel:manage:redemptions";
+ private const string SCOPES =
+ "openid channel:read:redemptions user:read:chat user:bot channel:moderate channel:manage:redemptions";
private readonly ILogger _logger;
private readonly ILoggerFactory _loggerFactory;
private readonly OidcClient _oidcClient;
public TwitchAuthConfig AuthConfig { get; }
- public TwitchAuthenticationService(IOptions config, ILoggerFactory loggerFactory)
+ public TwitchAuthenticationService(
+ IOptions config,
+ ILoggerFactory loggerFactory
+ )
{
AuthConfig = config.Value;
_loggerFactory = loggerFactory;
_logger = loggerFactory.CreateLogger();
- _oidcClient = new OidcClient(new OidcClientOptions
- {
- Authority = "https://id.twitch.tv/oauth2",
- ClientId = AuthConfig.ClientId,
- ClientSecret = AuthConfig.ClientSecret,
- RedirectUri = "http://localhost:5000",
- LoggerFactory = _loggerFactory,
- Scope = SCOPES,
- FilterClaims = false,
- Browser = new SystemBrowser(5000),
- });
+ _oidcClient = new OidcClient(
+ new OidcClientOptions
+ {
+ Authority = "https://id.twitch.tv/oauth2",
+ ClientId = AuthConfig.ClientId,
+ ClientSecret = AuthConfig.ClientSecret,
+ RedirectUri = "http://localhost:5000",
+ LoggerFactory = _loggerFactory,
+ Scope = SCOPES,
+ FilterClaims = false,
+ Browser = new SystemBrowser(5000),
+ }
+ );
}
public async Task RequestCredentials()
{
- if (string.IsNullOrEmpty(AuthConfig.AccessToken) ||
- AuthConfig.AccessTokenExpiration < DateTimeOffset.UtcNow)
+ if (
+ string.IsNullOrEmpty(AuthConfig.AccessToken)
+ || AuthConfig.AccessTokenExpiration < DateTimeOffset.UtcNow
+ )
{
_logger.LogInformation("Requesting Twitch credentials");
@@ -63,19 +71,25 @@ public async Task RequestCredentials()
public async Task IsTokenValidAsync()
{
- if (string.IsNullOrEmpty(AuthConfig.AccessToken) ||
- AuthConfig.AccessTokenExpiration < DateTimeOffset.UtcNow)
+ if (
+ string.IsNullOrEmpty(AuthConfig.AccessToken)
+ || AuthConfig.AccessTokenExpiration < DateTimeOffset.UtcNow
+ )
return false;
using var http = new HttpClient();
- http.DefaultRequestHeaders.Authorization =
- new System.Net.Http.Headers.AuthenticationHeaderValue("OAuth", AuthConfig.AccessToken);
+ http.DefaultRequestHeaders.Authorization =
+ new System.Net.Http.Headers.AuthenticationHeaderValue(
+ "OAuth",
+ AuthConfig.AccessToken
+ );
var res = await http.GetAsync("https://id.twitch.tv/oauth2/validate");
return res.IsSuccessStatusCode;
}
public async Task EnsureValidTokenAsync()
{
- if (await IsTokenValidAsync()) return;
+ if (await IsTokenValidAsync())
+ return;
if (!string.IsNullOrEmpty(AuthConfig.RefreshToken))
await RefreshCredentials();
diff --git a/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationProvider.cs b/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationProvider.cs
index 55c939b..364616f 100644
--- a/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationProvider.cs
+++ b/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationProvider.cs
@@ -1,6 +1,4 @@
-using ArcadePointsBot.Auth;
-using Microsoft.Extensions.Configuration.Json;
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -8,28 +6,34 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
+using ArcadePointsBot.Auth;
+using Microsoft.Extensions.Configuration.Json;
namespace ArcadePointsBot.Config
{
internal class WritableJsonConfigurationProvider : JsonConfigurationProvider
{
- public WritableJsonConfigurationProvider(JsonConfigurationSource source) : base(source) { }
+ public WritableJsonConfigurationProvider(JsonConfigurationSource source)
+ : base(source) { }
public override void Set(string key, string? value)
{
base.Set(key, value);
- if (Source.FileProvider == null) throw new InvalidOperationException("The FileProvider cannot be null");
- if (string.IsNullOrEmpty(Source.Path)) throw new InvalidOperationException("The Sourcepath cannot be null");
+ if (Source.FileProvider == null)
+ throw new InvalidOperationException("The FileProvider cannot be null");
+ if (string.IsNullOrEmpty(Source.Path))
+ throw new InvalidOperationException("The Sourcepath cannot be null");
var fullPath = Source.FileProvider.GetFileInfo(Source.Path).PhysicalPath;
var json = File.ReadAllText(fullPath!);
var config = JsonNode.Parse(json);
- if (config is null) throw new JsonException("Malformed app config");
+ if (config is null)
+ throw new JsonException("Malformed app config");
var configObj = config.AsObject();
var keyParts = key.Split(':');
if (keyParts.Length > 1)
{
- if(configObj[keyParts[0]] is null)
+ if (configObj[keyParts[0]] is null)
configObj[keyParts[0]] = new JsonObject();
configObj[keyParts[0]]![keyParts[1]] = value;
}
@@ -37,10 +41,10 @@ public override void Set(string key, string? value)
{
configObj[key] = value;
}
- File.WriteAllText(fullPath!, configObj.ToJsonString(new JsonSerializerOptions
- {
- WriteIndented = true
- }));
+ File.WriteAllText(
+ fullPath!,
+ configObj.ToJsonString(new JsonSerializerOptions { WriteIndented = true })
+ );
}
}
diff --git a/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationSource.cs b/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationSource.cs
index d398844..2258390 100644
--- a/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationSource.cs
+++ b/src/ArcadePointsBot/Infrastructure/Config/WritableJsonConfigurationSource.cs
@@ -1,10 +1,10 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Configuration.Json;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration.Json;
namespace ArcadePointsBot.Config
{
diff --git a/src/ArcadePointsBot/Infrastructure/Interop/Windows/NativeMethods.cs b/src/ArcadePointsBot/Infrastructure/Interop/Windows/NativeMethods.cs
index f82397c..9bf1017 100644
--- a/src/ArcadePointsBot/Infrastructure/Interop/Windows/NativeMethods.cs
+++ b/src/ArcadePointsBot/Infrastructure/Interop/Windows/NativeMethods.cs
@@ -1,11 +1,11 @@
//https://gist.github.com/DrustZ/640912b9d5cb745a3a56971c9bd58ac7
-using Avalonia.Input;
-using Avalonia.Win32.Input;
using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
+using Avalonia.Input;
+using Avalonia.Win32.Input;
namespace ArcadePointsBot.Interop.Windows;
@@ -50,6 +50,7 @@ internal struct INPUTUNION
{
[FieldOffset(0)]
internal MOUSEINPUT mouseInput;
+
[FieldOffset(0)]
internal KEYBDINPUT keyboardInput;
};
@@ -106,6 +107,7 @@ internal enum SendMouseInputFlags
#endregion
}
+
[SupportedOSPlatform("windows")]
public static class Keyboard
{
@@ -153,7 +155,8 @@ private static void SendKeyboardInput(Key key, bool press)
NativeMethods.INPUT ki = new NativeMethods.INPUT();
ki.type = NativeMethods.InputKeyboard;
ki.union.keyboardInput.wVk = (short)KeyInterop.VirtualKeyFromKey(key);
- ki.union.keyboardInput.wScan = (short)NativeMethods.MapVirtualKey(ki.union.keyboardInput.wVk, 0);
+ ki.union.keyboardInput.wScan = (short)
+ NativeMethods.MapVirtualKey(ki.union.keyboardInput.wVk, 0);
int dwFlags = 0;
@@ -189,27 +192,29 @@ private static void SendKeyboardInput(Key key, bool press)
// CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP,
// PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK
// key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in
- // the numeric keypad. The extended-key flag is set if the key is an extended key.
+ // the numeric keypad. The extended-key flag is set if the key is an extended key.
//
// - docs appear to be incorrect. Use of Spy++ indicates that break is not an extended key.
// Also, menu key and windows keys also appear to be extended.
- private static readonly Key[] ExtendedKeys = new Key[] {
- Key.RightAlt,
- Key.RightCtrl,
- Key.NumLock,
- Key.Insert,
- Key.Delete,
- Key.Home,
- Key.End,
- Key.Prior,
- Key.Next,
- Key.Up,
- Key.Down,
- Key.Left,
- Key.Right,
- Key.Apps,
- Key.RWin,
- Key.LWin };
+ private static readonly Key[] ExtendedKeys = new Key[]
+ {
+ Key.RightAlt,
+ Key.RightCtrl,
+ Key.NumLock,
+ Key.Insert,
+ Key.Delete,
+ Key.Home,
+ Key.End,
+ Key.Prior,
+ Key.Next,
+ Key.Up,
+ Key.Down,
+ Key.Left,
+ Key.Right,
+ Key.Apps,
+ Key.RWin,
+ Key.LWin
+ };
// Note that there are no distinct values for the following keys:
// numpad divide
// numpad enter
@@ -217,7 +222,6 @@ private static void SendKeyboardInput(Key key, bool press)
#endregion
}
-
[SupportedOSPlatform("windows")]
public static class Mouse
{
@@ -226,11 +230,13 @@ public static void Click(MouseButton mouseButton)
Down(mouseButton);
Up(mouseButton);
}
+
public static void DoubleClick(MouseButton mouseButton)
{
Click(mouseButton);
Click(mouseButton);
}
+
public static void Down(MouseButton mouseButton)
{
switch (mouseButton)
@@ -245,15 +251,22 @@ public static void Down(MouseButton mouseButton)
SendMouseButtonInput(NativeMethods.SendMouseInputFlags.MiddleDown);
break;
case MouseButton.XButton1:
- SendMouseButtonInput(NativeMethods.SendMouseInputFlags.XDown, NativeMethods.XButton1);
+ SendMouseButtonInput(
+ NativeMethods.SendMouseInputFlags.XDown,
+ NativeMethods.XButton1
+ );
break;
case MouseButton.XButton2:
- SendMouseButtonInput(NativeMethods.SendMouseInputFlags.XDown, NativeMethods.XButton2);
+ SendMouseButtonInput(
+ NativeMethods.SendMouseInputFlags.XDown,
+ NativeMethods.XButton2
+ );
break;
default:
throw new InvalidOperationException("Unsupported MouseButton input.");
}
}
+
public static void Up(MouseButton mouseButton)
{
switch (mouseButton)
@@ -287,7 +300,11 @@ private static void SendMouseButtonInput(NativeMethods.SendMouseInputFlags flags
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
- private static NativeMethods.INPUT CreateMouseInput(NativeMethods.SendMouseInputFlags flags, int data = 0)
+
+ private static NativeMethods.INPUT CreateMouseInput(
+ NativeMethods.SendMouseInputFlags flags,
+ int data = 0
+ )
{
int intflags = (int)flags;
@@ -295,10 +312,7 @@ private static NativeMethods.INPUT CreateMouseInput(NativeMethods.SendMouseInput
{
intflags |= NativeMethods.MouseeventfVirtualdesk;
}
- NativeMethods.INPUT mi = new()
- {
- type = NativeMethods.InputMouse
- };
+ NativeMethods.INPUT mi = new() { type = NativeMethods.InputMouse };
mi.union.mouseInput.dx = 0;
mi.union.mouseInput.dy = 0;
mi.union.mouseInput.mouseData = data;
@@ -307,4 +321,4 @@ private static NativeMethods.INPUT CreateMouseInput(NativeMethods.SendMouseInput
mi.union.mouseInput.dwExtraInfo = new IntPtr(0);
return mi;
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Infrastructure/SystemBrowser.cs b/src/ArcadePointsBot/Infrastructure/SystemBrowser.cs
index d4ef11e..863302b 100644
--- a/src/ArcadePointsBot/Infrastructure/SystemBrowser.cs
+++ b/src/ArcadePointsBot/Infrastructure/SystemBrowser.cs
@@ -1,18 +1,19 @@
-using IdentityModel.OidcClient.Browser;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
-using System;
+using System;
using System.Diagnostics;
-using System.Net.Sockets;
+using System.IO;
using System.Net;
+using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using System.IO;
+using IdentityModel.OidcClient.Browser;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
namespace ArcadePointsBot;
+
public class SystemBrowser : IBrowser
{
public int Port { get; }
@@ -41,7 +42,10 @@ private int GetRandomUnusedPort()
return port;
}
- public async Task InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default(CancellationToken))
+ public async Task InvokeAsync(
+ BrowserOptions options,
+ CancellationToken cancellationToken = default(CancellationToken)
+ )
{
using (var listener = new LoopbackHttpListener(Port, _path))
{
@@ -52,18 +56,34 @@ private int GetRandomUnusedPort()
var result = await listener.WaitForCallbackAsync();
if (string.IsNullOrWhiteSpace(result))
{
- return new BrowserResult { ResultType = BrowserResultType.UnknownError, Error = "Empty response." };
+ return new BrowserResult
+ {
+ ResultType = BrowserResultType.UnknownError,
+ Error = "Empty response."
+ };
}
- return new BrowserResult { Response = result, ResultType = BrowserResultType.Success };
+ return new BrowserResult
+ {
+ Response = result,
+ ResultType = BrowserResultType.Success
+ };
}
catch (TaskCanceledException ex)
{
- return new BrowserResult { ResultType = BrowserResultType.Timeout, Error = ex.Message };
+ return new BrowserResult
+ {
+ ResultType = BrowserResultType.Timeout,
+ Error = ex.Message
+ };
}
catch (Exception ex)
{
- return new BrowserResult { ResultType = BrowserResultType.UnknownError, Error = ex.Message };
+ return new BrowserResult
+ {
+ ResultType = BrowserResultType.UnknownError,
+ Error = ex.Message
+ };
}
}
}
@@ -80,7 +100,9 @@ public static void OpenBrowser(string url)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
url = url.Replace("&", "^&");
- Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
+ Process.Start(
+ new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }
+ );
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
@@ -111,15 +133,12 @@ public class LoopbackHttpListener : IDisposable
public LoopbackHttpListener(int port, string? path = null)
{
path ??= string.Empty;
- if (path.StartsWith("/")) path = path[1..];
+ if (path.StartsWith("/"))
+ path = path[1..];
_url = $"http://127.0.0.1:{port}/{path}";
- _host = new WebHostBuilder()
- .UseKestrel()
- .UseUrls(_url)
- .Configure(Configure)
- .Build();
+ _host = new WebHostBuilder().UseKestrel().UseUrls(_url).Configure(Configure).Build();
_host.Start();
}
@@ -142,7 +161,12 @@ void Configure(IApplicationBuilder app)
}
else if (ctx.Request.Method == "POST")
{
- if (!ctx.Request.ContentType!.Equals("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
+ if (
+ !ctx.Request.ContentType!.Equals(
+ "application/x-www-form-urlencoded",
+ StringComparison.OrdinalIgnoreCase
+ )
+ )
{
ctx.Response.StatusCode = 415;
}
diff --git a/src/ArcadePointsBot/Program.cs b/src/ArcadePointsBot/Program.cs
index acb6482..42bb67a 100644
--- a/src/ArcadePointsBot/Program.cs
+++ b/src/ArcadePointsBot/Program.cs
@@ -1,27 +1,28 @@
-using Avalonia;
-using Avalonia.ReactiveUI;
-using System;
+using System;
using System.Globalization;
+using Avalonia;
+using Avalonia.ReactiveUI;
namespace ArcadePointsBot
{
internal class Program
{
public static IServiceProvider ServiceProvider { get; private set; } = null!;
+
// Initialization code. Don't use any Avalonia, third-party APIs or any
// 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()
- => AppBuilder.Configure()
- .UsePlatformDetect()
- .WithInterFont()
- .LogToTrace()
- .UseReactiveUI();
+ public static AppBuilder BuildAvaloniaApp() =>
+ AppBuilder
+ .Configure()
+ .UsePlatformDetect()
+ .WithInterFont()
+ .LogToTrace()
+ .UseReactiveUI();
}
}
diff --git a/src/ArcadePointsBot/Util/EnumUtils.cs b/src/ArcadePointsBot/Util/EnumUtils.cs
index 7938fad..8a8899c 100644
--- a/src/ArcadePointsBot/Util/EnumUtils.cs
+++ b/src/ArcadePointsBot/Util/EnumUtils.cs
@@ -1,43 +1,57 @@
-using Avalonia;
-using Avalonia.Data.Converters;
-using System;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
+using Avalonia;
+using Avalonia.Data.Converters;
namespace ArcadePointsBot.Util;
public static class EnumUtils
{
- public static IEnumerable GetValues() where T : Enum
- => typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static).Select(x => x.GetValue(typeof(T)));
+ public static IEnumerable GetValues()
+ where T : Enum =>
+ typeof(T)
+ .GetFields(BindingFlags.Public | BindingFlags.Static)
+ .Select(x => x.GetValue(typeof(T)));
public static EnumDescription ToDescription(this Enum value)
{
string? description;
string? help = null;
-
- var attributes = value.GetType().GetField(value.ToString())?.GetCustomAttributes(typeof(DescriptionAttribute), false);
+
+ var attributes = value
+ .GetType()
+ .GetField(value.ToString())
+ ?.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes?.Any() ?? false)
{
- description = Resources.Enums.ResourceManager.GetString((attributes.First() as DescriptionAttribute)!.Description, Resources.Enums.Culture);
+ description = Resources.Enums.ResourceManager.GetString(
+ (attributes.First() as DescriptionAttribute)!.Description,
+ Resources.Enums.Culture
+ );
}
else
{
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
description = ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
}
-
- if(description!.IndexOf(';') is var index && index != -1)
+
+ if (description!.IndexOf(';') is var index && index != -1)
{
help = description.Substring(index + 1);
description = description.Substring(0, index);
}
- return new EnumDescription() { Value = value, Description = description, Help = help };
+ return new EnumDescription()
+ {
+ Value = value,
+ Description = description,
+ Help = help
+ };
}
}
@@ -89,24 +103,32 @@ public class EnumDescriptionConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
- if(value is null) return null;
+ if (value is null)
+ return null;
if (value.GetType().IsEnum)
{
return ((Enum)value).ToDescription();
}
throw new ArgumentException("Convert:Value must be an enum.");
}
-
- public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+
+ public object? ConvertBack(
+ object? value,
+ Type targetType,
+ object? parameter,
+ CultureInfo culture
+ )
{
- if(value is null) return null;
- if(value is EnumDescription enumDescription)
+ if (value is null)
+ return null;
+ if (value is EnumDescription enumDescription)
{
return enumDescription.Value;
}
throw new ArgumentException("ConvertBack:EnumDescription must be an enum.");
}
}
+
public class EnumDescriptionsConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
@@ -122,10 +144,15 @@ public class EnumDescriptionsConverter : IValueConverter
}
throw new ArgumentException("Convert:Value must be an enum.");
}
-
- public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+
+ public object? ConvertBack(
+ object? value,
+ Type targetType,
+ object? parameter,
+ CultureInfo culture
+ )
{
- if(value is IEnumerable enumDescriptions)
+ if (value is IEnumerable enumDescriptions)
{
return enumDescriptions.Select(x => x.Value);
}
@@ -137,12 +164,12 @@ public record EnumDescription
{
public object Value { get; set; } = null!;
- public string Description { get; set; }= null!;
-
+ public string Description { get; set; } = null!;
+
public string? Help { get; set; }
-
+
public override string ToString()
{
return Description;
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Util/ResourceHostExtensions.cs b/src/ArcadePointsBot/Util/ResourceHostExtensions.cs
index 0718062..ae26887 100644
--- a/src/ArcadePointsBot/Util/ResourceHostExtensions.cs
+++ b/src/ArcadePointsBot/Util/ResourceHostExtensions.cs
@@ -1,10 +1,10 @@
-using Avalonia.Controls;
-using Microsoft.Extensions.DependencyInjection;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Avalonia.Controls;
+using Microsoft.Extensions.DependencyInjection;
namespace ArcadePointsBot.Util
{
@@ -14,13 +14,15 @@ internal static class ResourceHostExtensions
// https://www.reddit.com/r/AvaloniaUI/comments/ssplp9/comment/hx0e3zi/?utm_source=share&utm_medium=web2x&context=3
public static IServiceProvider GetServiceProvider(this IResourceHost control)
{
- return (IServiceProvider?)control.FindResource(typeof(IServiceProvider)) ??
- throw new Exception("Expected service provider missing");
+ return (IServiceProvider?)control.FindResource(typeof(IServiceProvider))
+ ?? throw new Exception("Expected service provider missing");
}
public static T CreateInstance(this IResourceHost control)
{
- return ActivatorUtilities.CreateInstance(control.GetServiceProvider().CreateScope().ServiceProvider);
+ return ActivatorUtilities.CreateInstance(
+ control.GetServiceProvider().CreateScope().ServiceProvider
+ );
}
}
}
diff --git a/src/ArcadePointsBot/ViewLocator.cs b/src/ArcadePointsBot/ViewLocator.cs
index 76c7825..cdbdbf4 100644
--- a/src/ArcadePointsBot/ViewLocator.cs
+++ b/src/ArcadePointsBot/ViewLocator.cs
@@ -1,23 +1,28 @@
-using Avalonia.Controls;
-using Avalonia.Controls.Templates;
-using ArcadePointsBot.ViewModels;
-using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
+using ArcadePointsBot.ViewModels;
+using Avalonia.Controls;
+using Avalonia.Controls.Templates;
+using Microsoft.Extensions.DependencyInjection;
namespace ArcadePointsBot
{
public static class ViewLocatorHelpers
{
- public static IServiceCollection AddView(this IServiceCollection services)
+ public static IServiceCollection AddView(
+ this IServiceCollection services
+ )
where TView : Control, new()
where TViewModel : ViewModelBase
{
- services.AddSingleton(new ViewLocator.ViewLocationDescriptor(typeof(TViewModel), () => new TView()));
+ services.AddSingleton(
+ new ViewLocator.ViewLocationDescriptor(typeof(TViewModel), () => new TView())
+ );
return services;
}
}
+
public class ViewLocator : IDataTemplate
{
private readonly Dictionary> _views;
@@ -28,7 +33,10 @@ public ViewLocator(IEnumerable descriptors)
}
public Control Build(object? param) => _views[param!.GetType()]();
- public bool Match(object? param) => param is not null && _views.ContainsKey(param.GetType());
+
+ public bool Match(object? param) =>
+ param is not null && _views.ContainsKey(param.GetType());
+
public record ViewLocationDescriptor(Type ViewModel, Func Factory);
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/ViewModels/CreateRewardWindowViewModel.cs b/src/ArcadePointsBot/ViewModels/CreateRewardWindowViewModel.cs
index 87f2a14..e9e9186 100644
--- a/src/ArcadePointsBot/ViewModels/CreateRewardWindowViewModel.cs
+++ b/src/ArcadePointsBot/ViewModels/CreateRewardWindowViewModel.cs
@@ -1,4 +1,10 @@
-using ArcadePointsBot.Domain.Rewards;
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using ArcadePointsBot.Domain.Rewards;
using ArcadePointsBot.Services;
using ArcadePointsBot.Util;
using DynamicData;
@@ -6,12 +12,6 @@
using Microsoft.Extensions.DependencyInjection;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reactive;
-using System.Reactive.Linq;
-using System.Threading.Tasks;
namespace ArcadePointsBot.ViewModels
{
@@ -22,6 +22,7 @@ public partial class CreateRewardWindowViewModel : ViewModelBase
[Reactive]
public string? Title { get; set; }
+
[Reactive]
public string? Category { get; set; }
@@ -45,18 +46,34 @@ public partial class CreateRewardWindowViewModel : ViewModelBase
public CreateRewardWindowViewModel(IServiceProvider serviceProvider)
{
_serviceScope = serviceProvider.CreateScope();
- _pointRewardService = _serviceScope.ServiceProvider.GetRequiredService();
- Actions.ToObservableChangeSet(x => x).ToCollection().Select(x => x.Any()).ToPropertyEx(this, x => x.HasActions);
- CreateTwitchRewardCommand = ReactiveCommand.CreateFromTask(CreateTwitchReward,
+ _pointRewardService =
+ _serviceScope.ServiceProvider.GetRequiredService();
+ Actions
+ .ToObservableChangeSet(x => x)
+ .ToCollection()
+ .Select(x => x.Any())
+ .ToPropertyEx(this, x => x.HasActions);
+ CreateTwitchRewardCommand = ReactiveCommand.CreateFromTask(
+ CreateTwitchReward,
Observable.CombineLatest(
IsBusyObservable,
- this.WhenAnyValue(x => x.Title, x => x.Cost, x => x.HasActions, (title, cost, hasActions) =>
- !string.IsNullOrEmpty(title) && cost >= 10 && hasActions),
- (isBusy, a) =>
- isBusy && a));
- AddActionCommand = ReactiveCommand.Create(() => Actions.Add(new RewardActionViewModel(Actions.Count)));
+ this.WhenAnyValue(
+ x => x.Title,
+ x => x.Cost,
+ x => x.HasActions,
+ (title, cost, hasActions) =>
+ !string.IsNullOrEmpty(title) && cost >= 10 && hasActions
+ ),
+ (isBusy, a) => isBusy && a
+ )
+ );
+ AddActionCommand = ReactiveCommand.Create(
+ () => Actions.Add(new RewardActionViewModel(Actions.Count))
+ );
DupeActionCommand = ReactiveCommand.Create(DuplicateAction);
- RemoveActionCommand = ReactiveCommand.Create(action => Actions.Remove(action));
+ RemoveActionCommand = ReactiveCommand.Create(action =>
+ Actions.Remove(action)
+ );
}
void DuplicateAction(RewardActionViewModel action)
@@ -74,9 +91,14 @@ void DuplicateAction(RewardActionViewModel action)
async Task CreateTwitchReward()
{
Errors.Clear();
- var result = await _pointRewardService
- .CreateReward(Title!, Category, Cost, RequireInput, Actions);
- if(result.IsSuccess)
+ var result = await _pointRewardService.CreateReward(
+ Title!,
+ Category,
+ Cost,
+ RequireInput,
+ Actions
+ );
+ if (result.IsSuccess)
return result.Value;
Errors.Add(result.Error);
return null;
diff --git a/src/ArcadePointsBot/ViewModels/DesignData.cs b/src/ArcadePointsBot/ViewModels/DesignData.cs
index ab1e317..c1f846e 100644
--- a/src/ArcadePointsBot/ViewModels/DesignData.cs
+++ b/src/ArcadePointsBot/ViewModels/DesignData.cs
@@ -1,25 +1,30 @@
-using Avalonia;
+using System.Diagnostics;
+using System.Threading;
using ArcadePointsBot;
using ArcadePointsBot.Services;
using ArcadePointsBot.ViewModels;
+using Avalonia;
using Microsoft.Extensions.DependencyInjection;
-using System.Diagnostics;
-using System.Threading;
namespace ArcadePointsBot;
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
///
/// Used by for the Designer as a source of generated view models
///
public static class DesignData
{
- public static MainWindowViewModel MainWindowViewModel { get; } =
- ((App)Avalonia.Application.Current!).GlobalHost!.Services.GetRequiredService();
-
+ public static MainWindowViewModel MainWindowViewModel { get; } =
+ (
+ (App)Avalonia.Application.Current!
+ ).GlobalHost!.Services.GetRequiredService();
public static CreateRewardWindowViewModel CreateRewardWindowViewModel { get; } =
- ((App)Avalonia.Application.Current!).GlobalHost!.Services.GetRequiredService();
+ (
+ (App)Avalonia.Application.Current!
+ ).GlobalHost!.Services.GetRequiredService();
- public static EditRewardViewModel EditRewardViewModel { get; } = new EditRewardViewModel(null,
- new ArcadePointsBot.Domain.Rewards.TwitchReward());
+ public static EditRewardViewModel EditRewardViewModel { get; } =
+ new EditRewardViewModel(null, new ArcadePointsBot.Domain.Rewards.TwitchReward());
}
+#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
diff --git a/src/ArcadePointsBot/ViewModels/EditRewardViewModel.cs b/src/ArcadePointsBot/ViewModels/EditRewardViewModel.cs
index 4d1d0f7..1042ffb 100644
--- a/src/ArcadePointsBot/ViewModels/EditRewardViewModel.cs
+++ b/src/ArcadePointsBot/ViewModels/EditRewardViewModel.cs
@@ -1,4 +1,11 @@
-using ArcadePointsBot.Domain.Rewards;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using ArcadePointsBot.Domain.Rewards;
using ArcadePointsBot.Services;
using ArcadePointsBot.Util;
using DynamicData;
@@ -6,13 +13,6 @@
using Microsoft.Extensions.DependencyInjection;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reactive;
-using System.Reactive.Linq;
-using System.Threading.Tasks;
namespace ArcadePointsBot.ViewModels;
@@ -20,8 +20,10 @@ public partial class EditRewardViewModel : ViewModelBase
{
private readonly TwitchPointRewardService _pointRewardService;
private readonly TwitchReward _oldReward;
+
[Reactive]
public string Title { get; set; }
+
[Reactive]
public string? Category { get; set; }
@@ -51,20 +53,40 @@ public EditRewardViewModel(TwitchPointRewardService pointRewardService, TwitchRe
Cost = _oldReward.Cost;
RequireInput = _oldReward.RequireInput;
- Actions = new(new List()
+ Actions = new(
+ new List()
.Concat(reward.KeyboardActions.Select(RewardActionViewModel.FromAction))
- .Concat(reward.MouseActions.Select(RewardActionViewModel.FromAction)).OrderBy(x => x.Index).ToList());
- Actions.ToObservableChangeSet(x => x).ToCollection().Select(x => x.Any()).ToPropertyEx(this, x => x.HasActions);
+ .Concat(reward.MouseActions.Select(RewardActionViewModel.FromAction))
+ .OrderBy(x => x.Index)
+ .ToList()
+ );
+ Actions
+ .ToObservableChangeSet(x => x)
+ .ToCollection()
+ .Select(x => x.Any())
+ .ToPropertyEx(this, x => x.HasActions);
- EditTwitchRewardCommand = ReactiveCommand.CreateFromTask(EditTwitchReward,
+ EditTwitchRewardCommand = ReactiveCommand.CreateFromTask(
+ EditTwitchReward,
Observable.CombineLatest(
IsBusyObservable,
- this.WhenAnyValue(x => x.Title, x => x.Cost, x => x.HasActions, (title, cost, hasActions) =>
- !string.IsNullOrEmpty(title) && cost >= 10 && hasActions),
- (isBusy, a) => isBusy && a));
- AddActionCommand = ReactiveCommand.Create(() => Actions.Add(new RewardActionViewModel(Actions.Count)));
+ this.WhenAnyValue(
+ x => x.Title,
+ x => x.Cost,
+ x => x.HasActions,
+ (title, cost, hasActions) =>
+ !string.IsNullOrEmpty(title) && cost >= 10 && hasActions
+ ),
+ (isBusy, a) => isBusy && a
+ )
+ );
+ AddActionCommand = ReactiveCommand.Create(
+ () => Actions.Add(new RewardActionViewModel(Actions.Count))
+ );
DupeActionCommand = ReactiveCommand.Create(DuplicateAction);
- RemoveActionCommand = ReactiveCommand.Create(action => Actions.Remove(action));
+ RemoveActionCommand = ReactiveCommand.Create(action =>
+ Actions.Remove(action)
+ );
}
void DuplicateAction(RewardActionViewModel action)
@@ -92,4 +114,4 @@ void DuplicateAction(RewardActionViewModel action)
Errors.Add(result.Error);
return null;
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/ViewModels/KeyboardRewardActionVM.cs b/src/ArcadePointsBot/ViewModels/KeyboardRewardActionVM.cs
index cbd8306..13fbdfe 100644
--- a/src/ArcadePointsBot/ViewModels/KeyboardRewardActionVM.cs
+++ b/src/ArcadePointsBot/ViewModels/KeyboardRewardActionVM.cs
@@ -1,9 +1,9 @@
-using ArcadePointsBot.Domain.Rewards;
+using System.Collections;
+using ArcadePointsBot.Domain.Rewards;
using ArcadePointsBot.Util;
-using ReactiveUI.Fody.Helpers;
-using ReactiveUI;
-using System.Collections;
using Avalonia.Input;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
namespace ArcadePointsBot.ViewModels;
@@ -12,14 +12,17 @@ public class KeyboardRewardActionVM : ReactiveObject
public IEnumerable ActionValues { get; } = EnumUtils.GetValues();
public IEnumerable KeyValues { get; } = EnumUtils.GetValues();
- [Reactive] public int? Duration { get; set; }
- [Reactive] public KeyboardActionType? ActionType { get; set; }
- [Reactive] public Key? ActionKey { get; set; }
+ [Reactive]
+ public int? Duration { get; set; }
+
+ [Reactive]
+ public KeyboardActionType? ActionType { get; set; }
+
+ [Reactive]
+ public Key? ActionKey { get; set; }
public int Index { get; set; }
- public KeyboardRewardActionVM()
- {
- }
+ public KeyboardRewardActionVM() { }
public KeyboardRewardActionVM(int index)
{
diff --git a/src/ArcadePointsBot/ViewModels/MainWindowViewModel.cs b/src/ArcadePointsBot/ViewModels/MainWindowViewModel.cs
index afa70a8..01b5438 100644
--- a/src/ArcadePointsBot/ViewModels/MainWindowViewModel.cs
+++ b/src/ArcadePointsBot/ViewModels/MainWindowViewModel.cs
@@ -1,23 +1,23 @@
-using Avalonia.Collections;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Threading;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
using ArcadePointsBot.Auth;
+using ArcadePointsBot.Domain.Rewards;
using ArcadePointsBot.Services;
using ArcadePointsBot.Views;
+using Avalonia.Collections;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Threading;
using DynamicData;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reactive;
-using System.Reactive.Linq;
-using System.Threading.Tasks;
-using ArcadePointsBot.Domain.Rewards;
namespace ArcadePointsBot.ViewModels
{
@@ -47,36 +47,59 @@ public bool IsAuthed
public MainWindowViewModel(IServiceProvider serviceProvider, TwitchWorker worker)
{
_serviceScope = serviceProvider.CreateScope();
- _authenticationService = _serviceScope.ServiceProvider.GetRequiredService();
- _rewardService = _serviceScope.ServiceProvider.GetRequiredService();
+ _authenticationService =
+ _serviceScope.ServiceProvider.GetRequiredService();
+ _rewardService =
+ _serviceScope.ServiceProvider.GetRequiredService();
StatusText = "Checking Auth status";
_worker = worker;
_worker.PropertyChanged += WorkerPropertyChanged;
-
-
- CreateRewardCommand = ReactiveCommand.CreateFromTask(CreateReward,
- Observable.CombineLatest(IsBusyObservable, this.WhenAny(x => x.IsAuthed, x => x.Value), (isBusy, isAuthed) => isBusy && isAuthed));
- EditRewardCommand = ReactiveCommand.CreateFromTask(EditReward,
- Observable.CombineLatest(IsBusyObservable, this.WhenAny(x => x.IsAuthed, x => x.Value), (isBusy, isAuthed) => isBusy && isAuthed));
- DeleteRewardCommand = ReactiveCommand.CreateFromTask(DeleteReward, IsBusyObservable);
+ CreateRewardCommand = ReactiveCommand.CreateFromTask(
+ CreateReward,
+ Observable.CombineLatest(
+ IsBusyObservable,
+ this.WhenAny(x => x.IsAuthed, x => x.Value),
+ (isBusy, isAuthed) => isBusy && isAuthed
+ )
+ );
+ EditRewardCommand = ReactiveCommand.CreateFromTask(
+ EditReward,
+ Observable.CombineLatest(
+ IsBusyObservable,
+ this.WhenAny(x => x.IsAuthed, x => x.Value),
+ (isBusy, isAuthed) => isBusy && isAuthed
+ )
+ );
+ DeleteRewardCommand = ReactiveCommand.CreateFromTask(
+ DeleteReward,
+ IsBusyObservable
+ );
}
- private void WorkerPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
+ private void WorkerPropertyChanged(
+ object? sender,
+ System.ComponentModel.PropertyChangedEventArgs e
+ )
{
- if (e.PropertyName != nameof(_worker.Status)) return;
+ if (e.PropertyName != nameof(_worker.Status))
+ return;
WorkerStatus = _worker.Status;
}
private async Task CreateReward()
{
IsBusy = true;
- if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ if (
+ Avalonia.Application.Current?.ApplicationLifetime
+ is IClassicDesktopStyleApplicationLifetime desktop
+ )
{
var reward = await new CreateRewardWindow()
{
- DataContext = _serviceScope.ServiceProvider.GetRequiredService(),
+ DataContext =
+ _serviceScope.ServiceProvider.GetRequiredService(),
}.ShowDialog(desktop.MainWindow!);
if (reward != null)
{
@@ -89,11 +112,17 @@ private async Task CreateReward()
private async Task EditReward(TwitchReward reward)
{
IsBusy = true;
- if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ if (
+ Avalonia.Application.Current?.ApplicationLifetime
+ is IClassicDesktopStyleApplicationLifetime desktop
+ )
{
var res = await new EditRewardWindow()
{
- DataContext = new EditRewardViewModel(_rewardService, await _rewardService.GetReward(reward.Id)),
+ DataContext = new EditRewardViewModel(
+ _rewardService,
+ await _rewardService.GetReward(reward.Id)
+ ),
}.ShowDialog(desktop.MainWindow!);
if (res != null)
_rewardList.Replace(reward, res);
@@ -101,7 +130,6 @@ private async Task EditReward(TwitchReward reward)
IsBusy = false;
}
-
private async Task DeleteReward(TwitchReward reward)
{
IsBusy = true;
@@ -138,7 +166,10 @@ public async Task Login()
return;
}
- if (_authenticationService.AuthConfig.AccessTokenExpiration < System.DateTimeOffset.UtcNow)
+ if (
+ _authenticationService.AuthConfig.AccessTokenExpiration
+ < System.DateTimeOffset.UtcNow
+ )
{
StatusText = "Accestoken expired, refreshing token";
var result = await _authenticationService.RefreshCredentials();
@@ -161,11 +192,18 @@ public async void ChangeRewardEnabled(TwitchReward reward)
internal async Task BulkDisable(List toDisableIds)
{
- if(toDisableIds.Count == 0) return;
+ if (toDisableIds.Count == 0)
+ return;
await _rewardService.BulkUpdateRewards(
_rewardList
- .Where(x => toDisableIds.Contains(x.Id))
- .Select(x => { x.IsEnabled = false; return x; }), u => u.SetProperty(p => p.IsEnabled, false));
+ .Where(x => toDisableIds.Contains(x.Id))
+ .Select(x =>
+ {
+ x.IsEnabled = false;
+ return x;
+ }),
+ u => u.SetProperty(p => p.IsEnabled, false)
+ );
//foreach (var id in toDisableIds)
//{
// var reward = _rewardList.FirstOrDefault(x => x.Id == id);
@@ -177,11 +215,18 @@ await _rewardService.BulkUpdateRewards(
internal async Task BulkEnable(List toEnableIds)
{
- if(toEnableIds.Count == 0) return;
+ if (toEnableIds.Count == 0)
+ return;
await _rewardService.BulkUpdateRewards(
_rewardList
- .Where(x => toEnableIds.Contains(x.Id))
- .Select(x => { x.IsEnabled = true; return x; }), u => u.SetProperty(p => p.IsEnabled, true));
+ .Where(x => toEnableIds.Contains(x.Id))
+ .Select(x =>
+ {
+ x.IsEnabled = true;
+ return x;
+ }),
+ u => u.SetProperty(p => p.IsEnabled, true)
+ );
//foreach (var id in toEnableIds)
//{
// var reward = _rewardList.FirstOrDefault(x => x.Id == id);
@@ -195,9 +240,13 @@ internal async void StopWorker()
{
await _worker.StopAsync(default);
}
+
internal void StartWorker()
{
- Task.Factory.StartNew(async () => await _worker.StartAsync(default), TaskCreationOptions.LongRunning);
+ Task.Factory.StartNew(
+ async () => await _worker.StartAsync(default),
+ TaskCreationOptions.LongRunning
+ );
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/ViewModels/MouseRewardActionVM.cs b/src/ArcadePointsBot/ViewModels/MouseRewardActionVM.cs
index b61ff48..accd5c8 100644
--- a/src/ArcadePointsBot/ViewModels/MouseRewardActionVM.cs
+++ b/src/ArcadePointsBot/ViewModels/MouseRewardActionVM.cs
@@ -1,9 +1,9 @@
-using ArcadePointsBot.Domain.Rewards;
+using System.Collections;
+using ArcadePointsBot.Domain.Rewards;
using ArcadePointsBot.Util;
-using ReactiveUI.Fody.Helpers;
-using ReactiveUI;
-using System.Collections;
using Avalonia.Input;
+using ReactiveUI;
+using ReactiveUI.Fody.Helpers;
namespace ArcadePointsBot.ViewModels;
@@ -12,14 +12,17 @@ public class MouseRewardActionVM : ReactiveObject
public IEnumerable ActionValues { get; } = EnumUtils.GetValues();
public IEnumerable KeyValues { get; } = EnumUtils.GetValues();
- [Reactive] public int? Duration { get; set; }
- [Reactive] public MouseActionType? ActionType { get; set; }
- [Reactive] public MouseButton? ActionKey { get; set; }
+ [Reactive]
+ public int? Duration { get; set; }
+
+ [Reactive]
+ public MouseActionType? ActionType { get; set; }
+
+ [Reactive]
+ public MouseButton? ActionKey { get; set; }
public int Index { get; set; }
- public MouseRewardActionVM()
- {
- }
+ public MouseRewardActionVM() { }
public MouseRewardActionVM(int index)
{
diff --git a/src/ArcadePointsBot/ViewModels/RewardActionViewModel.cs b/src/ArcadePointsBot/ViewModels/RewardActionViewModel.cs
index e0ffd17..3f66fda 100644
--- a/src/ArcadePointsBot/ViewModels/RewardActionViewModel.cs
+++ b/src/ArcadePointsBot/ViewModels/RewardActionViewModel.cs
@@ -1,27 +1,31 @@
-using ReactiveUI;
-using ArcadePointsBot.Util;
+using System;
using System.Collections;
+using ArcadePointsBot.Domain.Rewards;
+using ArcadePointsBot.Util;
using Avalonia.Input;
+using ReactiveUI;
using ReactiveUI.Fody.Helpers;
-using System;
-using ArcadePointsBot.Domain.Rewards;
namespace ArcadePointsBot.ViewModels;
public class RewardActionViewModel : ReactiveObject
{
public string? Id { get; init; }
- [Reactive] public int? Duration { get; set; }
- [Reactive] public ActionType? ActionType { get; set; }
- [Reactive] public Enum? ActionKeyType { get; set; }
- [Reactive] public Enum? ActionKey { get; set; }
- public int Index { get; set; }
+ [Reactive]
+ public int? Duration { get; set; }
- public RewardActionViewModel()
- {
+ [Reactive]
+ public ActionType? ActionType { get; set; }
- }
+ [Reactive]
+ public Enum? ActionKeyType { get; set; }
+
+ [Reactive]
+ public Enum? ActionKey { get; set; }
+ public int Index { get; set; }
+
+ public RewardActionViewModel() { }
public RewardActionViewModel(int index)
{
diff --git a/src/ArcadePointsBot/ViewModels/ViewModelBase.cs b/src/ArcadePointsBot/ViewModels/ViewModelBase.cs
index c3c511d..cddc797 100644
--- a/src/ArcadePointsBot/ViewModels/ViewModelBase.cs
+++ b/src/ArcadePointsBot/ViewModels/ViewModelBase.cs
@@ -1,13 +1,13 @@
-using ArcadePointsBot.Common.Primitives;
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive.Linq;
+using ArcadePointsBot.Common.Primitives;
using Avalonia.Threading;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reactive.Linq;
namespace ArcadePointsBot.ViewModels
{
@@ -19,7 +19,8 @@ public partial class ViewModelBase : ReactiveObject
public string? StatusText
{
get => _statusText;
- set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _statusText, value));
+ set =>
+ Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _statusText, value));
}
private bool _isBusy;
public bool IsBusy
@@ -27,7 +28,7 @@ public bool IsBusy
get => _isBusy;
set => Dispatcher.UIThread.Post(() => this.RaiseAndSetIfChanged(ref _isBusy, value));
}
-
+
[ObservableAsProperty]
public bool HasError { get; }
@@ -51,4 +52,4 @@ protected ViewModelBase()
public bool HasActions { get; }
Actions.ToObservableChangeSet(x => x).ToCollection().Select(x => x.Any()).ToPropertyEx(this, x => x.HasActions);
- */
\ No newline at end of file
+ */
diff --git a/src/ArcadePointsBot/Views/CreateRewardWindow.axaml.cs b/src/ArcadePointsBot/Views/CreateRewardWindow.axaml.cs
index 69e822d..55283c4 100644
--- a/src/ArcadePointsBot/Views/CreateRewardWindow.axaml.cs
+++ b/src/ArcadePointsBot/Views/CreateRewardWindow.axaml.cs
@@ -1,7 +1,7 @@
-using Avalonia.ReactiveUI;
+using System;
using ArcadePointsBot.ViewModels;
+using Avalonia.ReactiveUI;
using ReactiveUI;
-using System;
namespace ArcadePointsBot;
@@ -11,10 +11,14 @@ public CreateRewardWindow()
{
InitializeComponent();
- this.WhenActivated(d => d(ViewModel!.CreateTwitchRewardCommand.Subscribe(x =>
- {
- if (x != null)
- Close(x);
- })));
+ this.WhenActivated(d =>
+ d(
+ ViewModel!.CreateTwitchRewardCommand.Subscribe(x =>
+ {
+ if (x != null)
+ Close(x);
+ })
+ )
+ );
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Views/EditRewardWindow.axaml.cs b/src/ArcadePointsBot/Views/EditRewardWindow.axaml.cs
index c734e4a..8c33ff1 100644
--- a/src/ArcadePointsBot/Views/EditRewardWindow.axaml.cs
+++ b/src/ArcadePointsBot/Views/EditRewardWindow.axaml.cs
@@ -1,8 +1,8 @@
+using System;
+using ArcadePointsBot.ViewModels;
using Avalonia.Controls;
using Avalonia.ReactiveUI;
-using ArcadePointsBot.ViewModels;
using ReactiveUI;
-using System;
namespace ArcadePointsBot.Views
{
@@ -11,12 +11,17 @@ public partial class EditRewardWindow : ReactiveWindow
public EditRewardWindow()
{
InitializeComponent();
- if (Design.IsDesignMode) return;
- this.WhenActivated(d => d(ViewModel!.EditTwitchRewardCommand.Subscribe(x =>
- {
- if (x != null)
- Close(x);
- })));
+ if (Design.IsDesignMode)
+ return;
+ this.WhenActivated(d =>
+ d(
+ ViewModel!.EditTwitchRewardCommand.Subscribe(x =>
+ {
+ if (x != null)
+ Close(x);
+ })
+ )
+ );
}
}
}
diff --git a/src/ArcadePointsBot/Views/MainWindow.axaml.cs b/src/ArcadePointsBot/Views/MainWindow.axaml.cs
index 7718ba5..b3beb99 100644
--- a/src/ArcadePointsBot/Views/MainWindow.axaml.cs
+++ b/src/ArcadePointsBot/Views/MainWindow.axaml.cs
@@ -1,13 +1,13 @@
+using System.Globalization;
+using ArcadePointsBot.Domain.Rewards;
+using ArcadePointsBot.ViewModels;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
-using ArcadePointsBot.ViewModels;
-using ReactiveUI;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
-using System.Globalization;
-using ArcadePointsBot.Domain.Rewards;
+using Microsoft.Extensions.DependencyInjection;
+using ReactiveUI;
namespace ArcadePointsBot.Views
{
@@ -19,10 +19,10 @@ public MainWindow()
this.WhenActivated(disposables =>
{
-
Dispatcher.UIThread.Post(async () =>
{
- if (Design.IsDesignMode) return;
+ if (Design.IsDesignMode)
+ return;
await ViewModel!.Login();
await ViewModel!.LoadRewards();
});
@@ -37,18 +37,22 @@ void OnEnabledChanged(object sender, RoutedEventArgs e)
ViewModel!.ChangeRewardEnabled(reward);
}
}
+
void ChangeWorkerStatus(object sender, RoutedEventArgs e)
{
if (ViewModel!.WorkerStatus == ArcadePointsBot.WorkerStatus.Running)
ViewModel!.StopWorker();
- if (ViewModel!.WorkerStatus == ArcadePointsBot.WorkerStatus.Stopped ||
- ViewModel!.WorkerStatus == ArcadePointsBot.WorkerStatus.Errored )
+ if (
+ ViewModel!.WorkerStatus == ArcadePointsBot.WorkerStatus.Stopped
+ || ViewModel!.WorkerStatus == ArcadePointsBot.WorkerStatus.Errored
+ )
ViewModel!.StartWorker();
}
+
protected override void OnClosing(WindowClosingEventArgs e)
{
ViewModel?.StopWorker();
base.OnClosing(e);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ArcadePointsBot/Views/RewardActionView.axaml.cs b/src/ArcadePointsBot/Views/RewardActionView.axaml.cs
index 61da71d..1eb145a 100644
--- a/src/ArcadePointsBot/Views/RewardActionView.axaml.cs
+++ b/src/ArcadePointsBot/Views/RewardActionView.axaml.cs
@@ -10,4 +10,4 @@ public RewardActionView()
{
InitializeComponent();
}
-}
\ No newline at end of file
+}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 0000000..add7a90
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,7 @@
+
+
+