Compare commits
3 Commits
626b31a3ce
...
main
Author | SHA1 | Date |
---|---|---|
Gottfried Wilhelm Leibniz | 6a9c90ef4b | |
Gottfried Wilhelm Leibniz | 07672d3463 | |
Gottfried Wilhelm Leibniz | 64d18102be |
|
@ -0,0 +1,12 @@
|
||||||
|
using DataAccess.Models;
|
||||||
|
|
||||||
|
namespace DataAccess.Data;
|
||||||
|
|
||||||
|
public interface IUserData
|
||||||
|
{
|
||||||
|
Task<IEnumerable<UserModel>> GetUsers();
|
||||||
|
Task<UserModel?> GetUser(int id);
|
||||||
|
Task InsertUser(UserModel user);
|
||||||
|
Task UpdateUser(UserModel user);
|
||||||
|
Task DeleteUser(int id);
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using DataAccess.DbAccess;
|
||||||
|
using DataAccess.Models;
|
||||||
|
|
||||||
|
namespace DataAccess.Data;
|
||||||
|
|
||||||
|
public class UserData : IUserData
|
||||||
|
{
|
||||||
|
private readonly ISqlDataAccess _db;
|
||||||
|
|
||||||
|
public UserData(ISqlDataAccess db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<UserModel>> GetUsers()
|
||||||
|
{
|
||||||
|
return _db.LoadData<UserModel, dynamic>("dbo.spUser_GetAll", new { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<UserModel?> GetUser(int id)
|
||||||
|
{
|
||||||
|
IEnumerable<UserModel> results = await _db.LoadData<UserModel, dynamic>(
|
||||||
|
"dbo.spUser_Get",
|
||||||
|
new { Id = id });
|
||||||
|
|
||||||
|
return results.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task InsertUser(UserModel user)
|
||||||
|
{
|
||||||
|
return _db.SaveData("dbo.spUser_Insert", new { user.FirstName, user.LastName });
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdateUser(UserModel user)
|
||||||
|
{
|
||||||
|
return _db.SaveData("dbo.spUser_Update", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task DeleteUser(int id)
|
||||||
|
{
|
||||||
|
return _db.SaveData("dbo.spUser_Delete", new { Id = id });
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Dapper" Version="2.0.123" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||||
|
<PackageReference Include="System.Data.SqlClient" Version="4.8.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,33 @@
|
||||||
|
namespace DataAccess.DbAccess;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stellt Methoden zur Ausführung von CRUD-Operationen bereit.
|
||||||
|
/// </summary>
|
||||||
|
public interface ISqlDataAccess
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Liest Daten aus der Datenbank (Read Operationen).
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TData">Typ der Objekte die zurückgegeben werden.</typeparam>
|
||||||
|
/// <typeparam name="TParam">Typ des Objekts das die Parameter für die SQL-Query enthält.</typeparam>
|
||||||
|
/// <param name="storedProcedureName">Name der StoredProcedure die ausgeführt werden soll.</param>
|
||||||
|
/// <param name="parameters">Das Objekt das die Parameter enthält.</param>
|
||||||
|
/// <param name="connectionId">Der Name des ConnectionStrings der für die Verbindung verwendet werden soll.</param>
|
||||||
|
/// <returns>Die Ergebnisse der Anfrage.</returns>
|
||||||
|
Task<IEnumerable<TData>> LoadData<TData, TParam>(
|
||||||
|
string storedProcedureName,
|
||||||
|
TParam parameters,
|
||||||
|
string connectionId = "Default");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Führt eine SQL-Anfrage aus, die keinen Rückgabewert hat (Create, Update und Delete Operationen).
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TParam">Typ des Objekts das die Parameter für die SQL-Query enthält.</typeparam>
|
||||||
|
/// <param name="storedProcedureName">Name der StoredProcedure die ausgeführt werden soll.</param>
|
||||||
|
/// <param name="parameters">Das Objekt das die Parameter enthält.</param>
|
||||||
|
/// <param name="connectionId">Der Name des ConnectionStrings der für die Verbindung verwendet werden soll.</param>
|
||||||
|
Task SaveData<TParam>(
|
||||||
|
string storedProcedureName,
|
||||||
|
TParam parameters,
|
||||||
|
string connectionId = "Default");
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
|
||||||
|
namespace DataAccess.DbAccess;
|
||||||
|
|
||||||
|
public class SqlDataAccess : ISqlDataAccess
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _config;
|
||||||
|
|
||||||
|
public SqlDataAccess(IConfiguration config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<TData>> LoadData<TData, TParam>(
|
||||||
|
string storedProcedureName,
|
||||||
|
TParam parameters,
|
||||||
|
string connectionId = "Default")
|
||||||
|
{
|
||||||
|
using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId));
|
||||||
|
|
||||||
|
return await connection.QueryAsync<TData>(storedProcedureName, parameters,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveData<TParam>(
|
||||||
|
string storedProcedureName,
|
||||||
|
TParam parameters,
|
||||||
|
string connectionId = "Default")
|
||||||
|
{
|
||||||
|
using IDbConnection connection = new SqlConnection(_config.GetConnectionString(connectionId));
|
||||||
|
|
||||||
|
await connection.ExecuteAsync(storedProcedureName, parameters,
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace DataAccess.Models;
|
||||||
|
|
||||||
|
public class UserModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string FirstName { get; set; } = string.Empty;
|
||||||
|
public string LastName { get; set; } = string.Empty;
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<Name>GottfriedsNackenDB</Name>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectVersion>4.1</ProjectVersion>
|
||||||
|
<ProjectGuid>{79f8ac31-e467-4f7c-ac3b-cfadc3290750}</ProjectGuid>
|
||||||
|
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider</DSP>
|
||||||
|
<OutputType>Database</OutputType>
|
||||||
|
<RootPath>
|
||||||
|
</RootPath>
|
||||||
|
<RootNamespace>GottfriedsNackenDB</RootNamespace>
|
||||||
|
<AssemblyName>GottfriedsNackenDB</AssemblyName>
|
||||||
|
<ModelCollation>1033, CI</ModelCollation>
|
||||||
|
<DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>
|
||||||
|
<DeployToDatabase>True</DeployToDatabase>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<TargetLanguage>CS</TargetLanguage>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<SqlServerVerification>False</SqlServerVerification>
|
||||||
|
<IncludeCompositeObjects>True</IncludeCompositeObjects>
|
||||||
|
<TargetDatabaseSet>True</TargetDatabaseSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DefineDebug>false</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||||
|
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<DefineDebug>true</DefineDebug>
|
||||||
|
<DefineTrace>true</DefineTrace>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||||
|
<!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
|
||||||
|
<SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
|
||||||
|
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<Import Condition="'$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties" />
|
||||||
|
<Folder Include="dbo" />
|
||||||
|
<Folder Include="dbo\Tables" />
|
||||||
|
<Folder Include="dbo\StoredProcedures" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Build Include="dbo\Tables\User.sql" />
|
||||||
|
<Build Include="dbo\StoredProcedures\spUser_GetAll.sql" />
|
||||||
|
<Build Include="dbo\StoredProcedures\spUser_Get.sql" />
|
||||||
|
<Build Include="dbo\StoredProcedures\spUser_Delete.sql" />
|
||||||
|
<Build Include="dbo\StoredProcedures\spUser_Insert.sql" />
|
||||||
|
<Build Include="dbo\StoredProcedures\spUser_Update.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="GottfriedsNackenDB.publish.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PostDeploy Include="Script.PostDeployment.sql" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* Wird nur ausgeführt, wenn es keine Einträge in [dbo].[User] */
|
||||||
|
IF not exists (SELECT 1 FROM [dbo].[User])
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO [dbo].[User] (FirstName, LastName)
|
||||||
|
VALUES
|
||||||
|
('Gottfried Wilhelm', 'Leibniz'),
|
||||||
|
('Albert', 'Einstein'),
|
||||||
|
('Curry', 'Wurst'),
|
||||||
|
('Brat', 'Wurst')
|
||||||
|
END
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE PROCEDURE [dbo].[spUser_Delete]
|
||||||
|
@Id int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
DELETE
|
||||||
|
FROM [dbo].[User]
|
||||||
|
WHERE Id = @Id;
|
||||||
|
END
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE PROCEDURE [dbo].[spUser_Get]
|
||||||
|
@Id int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SELECT Id, FirstName, LastName
|
||||||
|
FROM [dbo].[User]
|
||||||
|
WHERE Id = @Id;
|
||||||
|
END
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE PROCEDURE [dbo].[spUser_GetAll]
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SELECT Id, FirstName, LastName
|
||||||
|
FROM [dbo].[User];
|
||||||
|
END
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE PROCEDURE [dbo].[spUser_Insert]
|
||||||
|
@FirstName nvarchar(50),
|
||||||
|
@LastName nvarchar(50)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO [dbo].[User] (FirstName, LastName)
|
||||||
|
VALUES (@FirstName, @LastName);
|
||||||
|
END
|
|
@ -0,0 +1,10 @@
|
||||||
|
CREATE PROCEDURE [dbo].[spUser_Update]
|
||||||
|
@Id int,
|
||||||
|
@FirstName nvarchar(50),
|
||||||
|
@LastName nvarchar(50)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
UPDATE [dbo].[User]
|
||||||
|
SET FirstName = @FirstName, LastName = @LastName
|
||||||
|
WHERE Id = @Id;
|
||||||
|
END
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE [dbo].[User]
|
||||||
|
(
|
||||||
|
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
|
||||||
|
[FirstName] NVARCHAR(50) NOT NULL,
|
||||||
|
[LastName] NVARCHAR(50) NOT NULL
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace GottfriedsNackenUtility;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bietet nütliche mathematische Funktionen.
|
||||||
|
/// </summary>
|
||||||
|
public static class MathHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeriert die Zahlen der Fibonacci-Folge.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Der Datentyp ist <see cref="BigInteger"/>, da es ein paar Fibonacci-Zahlen gibt die nicht von <see cref="int"/> dargestellt werden können.
|
||||||
|
/// </remarks>
|
||||||
|
public static IEnumerable<BigInteger> Fibonacci()
|
||||||
|
{
|
||||||
|
BigInteger i = 0;
|
||||||
|
BigInteger j = 1;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
BigInteger fib = i + j;
|
||||||
|
|
||||||
|
i = j;
|
||||||
|
j = fib;
|
||||||
|
|
||||||
|
yield return fib;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace GottfriedsNackenUtility;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hier sind suspiziöse Funktionen versteckt.
|
||||||
|
/// </summary>
|
||||||
|
public static class SusHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dies ist der ausgeklügelste fake-Fortschrittbalkensalgorithmus den die Welt je erblickt hat.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Dieser Task läuft in einer Endlosschleife und MUSS mit Hilfe des Abbruchtokens abgebrochen werden!
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="progressChangedCallback">Das callback das aufgerufen wird, wenn der Fortschritt sich geändert hat.
|
||||||
|
/// Gibt einen Int zwischen 0 und 100 zurück oder -1, wenn der Fortschrittsbalken auf einen "indefinite" Zustand wechseln soll.</param>
|
||||||
|
/// <param name="cancellationToken">Ein Abbruchtoken, das beim Warten auf den Abschluss der Aufgabe überwacht werden soll.</param>
|
||||||
|
public static async Task UpdateDefinitelyNotFakeProgress(Action<int> progressChangedCallback, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (BigInteger fibonacci in MathHelper.Fibonacci())
|
||||||
|
{
|
||||||
|
await Task.Delay(250 + (int)(fibonacci % 420), cancellationToken);
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fibonacci.IsEven && (int)(fibonacci % 42) == 0)
|
||||||
|
{
|
||||||
|
progressChangedCallback(-1);
|
||||||
|
await Task.Delay(1337, cancellationToken);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressChangedCallback((int)(fibonacci % 69));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,12 @@ VisualStudioVersion = 17.1.32210.238
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GottfriedsNackenWebseite", "GottfriedsNackenWebseite\GottfriedsNackenWebseite.csproj", "{464DD643-DAD9-4E16-BB24-36F789ED4C15}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GottfriedsNackenWebseite", "GottfriedsNackenWebseite\GottfriedsNackenWebseite.csproj", "{464DD643-DAD9-4E16-BB24-36F789ED4C15}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GottfriedsNackenUtility", "GottfriedsNackenUtility\GottfriedsNackenUtility.csproj", "{0122762F-9961-4D28-8AA9-0D6AE7630208}"
|
||||||
|
EndProject
|
||||||
|
Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "GottfriedsNackenDB", "GottfriedsNackenDB\GottfriedsNackenDB.sqlproj", "{79F8AC31-E467-4F7C-AC3B-CFADC3290750}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataAccess", "DataAccess\DataAccess.csproj", "{023715EE-C9DB-417F-9B77-28BF48A30D41}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -15,6 +21,20 @@ Global
|
||||||
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Release|Any CPU.Build.0 = Release|Any CPU
|
{464DD643-DAD9-4E16-BB24-36F789ED4C15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0122762F-9961-4D28-8AA9-0D6AE7630208}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0122762F-9961-4D28-8AA9-0D6AE7630208}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0122762F-9961-4D28-8AA9-0D6AE7630208}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0122762F-9961-4D28-8AA9-0D6AE7630208}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{79F8AC31-E467-4F7C-AC3B-CFADC3290750}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
|
{023715EE-C9DB-417F-9B77-28BF48A30D41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{023715EE-C9DB-417F-9B77-28BF48A30D41}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{023715EE-C9DB-417F-9B77-28BF48A30D41}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{023715EE-C9DB-417F-9B77-28BF48A30D41}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
@using System.Diagnostics
|
@using System.Diagnostics
|
||||||
|
|
||||||
<!-- Hidden Alerts -->
|
<!-- Hidden Alerts -->
|
||||||
<div hidden="@hideAlert">
|
<div hidden="@(_alert == AlertState.None)">
|
||||||
<MudContainer MaxWidth="MaxWidth.Small">
|
<MudContainer MaxWidth="MaxWidth.Small">
|
||||||
<MudGrid>
|
<MudGrid>
|
||||||
<MudItem xs="1"></MudItem>
|
<MudItem xs="1"></MudItem>
|
||||||
<MudItem xs="8">
|
<MudItem xs="8">
|
||||||
<MudAlert Severity="Severity.Success">Korrekt!</MudAlert>
|
@if (_alert == AlertState.Correct)
|
||||||
|
{
|
||||||
|
<MudAlert Severity="Severity.Success">Korrekt!</MudAlert>
|
||||||
|
}
|
||||||
|
else if (_alert == AlertState.Invalid)
|
||||||
|
{
|
||||||
|
<MudAlert Severity="Severity.Error">Eingabe ungültig!</MudAlert>
|
||||||
|
}
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="2">
|
<MudItem xs="2">
|
||||||
<MudIconButton Icon="@Icons.Filled.Replay" Color="Color.Primary" aria-label="nochmal spielen" OnClick="@PlayAgain"></MudIconButton>
|
@if (_alert == AlertState.Correct)
|
||||||
|
{
|
||||||
|
<MudIconButton Icon="@Icons.Filled.Replay" Color="Color.Primary" aria-label="nochmal spielen" OnClick="@PlayAgain" />
|
||||||
|
}
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="1"></MudItem>
|
<MudItem xs="1"></MudItem>
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
|
@ -19,7 +29,7 @@
|
||||||
<!-- Matrix mit Buchstabenfeldern -->
|
<!-- Matrix mit Buchstabenfeldern -->
|
||||||
<div class="d-flex justify-center mt-2 mb-2">
|
<div class="d-flex justify-center mt-2 mb-2">
|
||||||
<div>
|
<div>
|
||||||
@foreach (CharData[] guess in PreviousGuesses)
|
@foreach (CharData[] guess in _previousGuesses)
|
||||||
{
|
{
|
||||||
<div class="d-flex mb-2">
|
<div class="d-flex mb-2">
|
||||||
@foreach (CharData cd in guess)
|
@foreach (CharData cd in guess)
|
||||||
|
@ -48,25 +58,35 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>@Input</p>
|
@*
|
||||||
|
<MudTextField T="string" FullWidth="true" Immediate="true" @bind-Value="Input" Label="Bla" Variant="Variant.Outlined" MaxLength="ColumnCount" Counter="ColumnCount" />
|
||||||
|
<MudTextField T="string" FullWidth="true" Immediate="true" @bind-Value="Input" Label="Blub" Variant="Variant.Outlined" MaxLength="ColumnCount" Counter="ColumnCount" />
|
||||||
|
*@
|
||||||
<!-- Input dialogue feld -->
|
<!-- Input dialogue feld -->
|
||||||
<MudContainer MaxWidth="MaxWidth.Small" @onkeyup="@Check4Enter">
|
<MudContainer MaxWidth="MaxWidth.Small">
|
||||||
<MudGrid Spacing="2">
|
<MudGrid Spacing="2">
|
||||||
<MudItem xs="1"></MudItem>
|
<MudItem xs="1" />
|
||||||
<MudItem xs="8">
|
<MudItem xs="8">
|
||||||
<MudTextField Class="" @ref="textField" T="string" FullWidth="true" Immediate="true" @bind-Value="@_input" Label="Dein Tipp:" Variant="Variant.Outlined" MaxLength="5" Mask="@InputMask" Counter="ColumnCount" />
|
<MudTextField @ref="_textField" T="string" FullWidth="true" Immediate="true" @bind-Value="Input" Label="Dein Tipp:" Variant="Variant.Outlined" MaxLength="ColumnCount" Mask="@InputMask" Counter="ColumnCount" OnKeyDown="OnKeyDown" />
|
||||||
|
@*<input Type="text" value="@Input"/>*@
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="2">
|
<MudItem xs="2">
|
||||||
<MudButton style="height: 56px; margin-top: 6px;" Class="justify-center" Disabled="_input.Length != ColumnCount"
|
<MudButton style="height: 56px; margin-top: 6px;" Class="justify-center" Disabled="Input.Length != ColumnCount"
|
||||||
Size="Size.Large" Variant="Variant.Outlined" EndIcon="@Icons.Material.Filled.Send" Color="Color.Primary" OnClick=@ButtonOnClick>OK</MudButton>
|
Size="Size.Large" Variant="Variant.Outlined" EndIcon="@Icons.Material.Filled.Send" Color="Color.Primary" OnClick=@OnEnterGuessClick>OK</MudButton>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="1"></MudItem>
|
<MudItem xs="1" />
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
|
private enum AlertState
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Correct,
|
||||||
|
Invalid
|
||||||
|
}
|
||||||
|
|
||||||
public enum CharState
|
public enum CharState
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
@ -87,111 +107,87 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _input = string.Empty;
|
private bool _found = false;
|
||||||
|
|
||||||
|
private AlertState _alert = AlertState.None;
|
||||||
|
|
||||||
|
private List<CharData[]> _previousGuesses = new();
|
||||||
|
|
||||||
|
private MudTextField<string> _textField = default!;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Input
|
public string Input { get; set; } = String.Empty;
|
||||||
{
|
|
||||||
get => _input;
|
|
||||||
set => _input = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetText(string text)
|
|
||||||
{
|
|
||||||
textField.SetText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool hideAlert = true;
|
|
||||||
|
|
||||||
public MudTextField<string> textField;
|
|
||||||
|
|
||||||
public List<CharData[]> PreviousGuesses = new();
|
|
||||||
|
|
||||||
private bool found = false;
|
|
||||||
private int _columnCount;
|
|
||||||
private string? _secret = null;
|
|
||||||
private IMask _inputMask = new RegexMask(@"^[A-Za-z]{0,5}$");
|
|
||||||
private Func<string, bool>? _checkInput;
|
|
||||||
private Func<string>? _generateSecret;
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int ColumnCount
|
public int ColumnCount { get; set; }
|
||||||
{
|
|
||||||
get => _columnCount;
|
public string? Secret { get; set; } = null;
|
||||||
set => _columnCount = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string? Secret
|
public IMask InputMask { get; set; } = new RegexMask("^.*$");
|
||||||
{
|
|
||||||
get => _secret;
|
|
||||||
set => _secret = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prüft ob die getätigte Eingabe eine mögliche Lösung ist.
|
||||||
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public IMask InputMask
|
public Func<string, bool> CheckInput { get; set; } = _ => true;
|
||||||
{
|
|
||||||
get => _inputMask;
|
|
||||||
set => _inputMask = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public Func<string, bool>? CheckInput
|
|
||||||
{
|
|
||||||
get => _checkInput;
|
|
||||||
set => _checkInput = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public Func<string>? GenerateSecret
|
|
||||||
{
|
|
||||||
get => _generateSecret;
|
|
||||||
set => _generateSecret = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wird ausgelöst wenn eine Eingabe getätigt und validiert wurde.
|
/// Wird ausgelöst wenn eine Eingabe getätigt und validiert wurde.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<CharData[]>? InputValidated;
|
[Parameter]
|
||||||
|
public EventCallback<CharData[]> InputValidated { get; set; }
|
||||||
|
|
||||||
public void Check4Enter(KeyboardEventArgs e)
|
/// <summary>
|
||||||
|
/// Wird ausgelöst wenn ein neues Secret generiert werden muss.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback GenerateSecret { get; set; }
|
||||||
|
|
||||||
|
public async Task OnKeyDown(KeyboardEventArgs e)
|
||||||
{
|
{
|
||||||
|
_alert = AlertState.None;
|
||||||
|
|
||||||
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||||
{
|
{
|
||||||
if(found)
|
if(_found)
|
||||||
{
|
{
|
||||||
PlayAgain();
|
await PlayAgain();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ButtonOnClick();
|
await OnEnterGuessClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ButtonOnClick()
|
public async Task OnEnterGuessClick()
|
||||||
{
|
{
|
||||||
if (Input.Length != ColumnCount || found) return;
|
if (Input.Length != ColumnCount || _found) return;
|
||||||
|
|
||||||
if (CheckInput != null && !CheckInput(Input))
|
if (!CheckInput(Input))
|
||||||
return; // TODO: Eingabe ungültig!
|
|
||||||
|
|
||||||
if (Secret == null && GenerateSecret != null)
|
|
||||||
Secret = GenerateSecret();
|
|
||||||
|
|
||||||
if(TestInput(Input))
|
|
||||||
{
|
{
|
||||||
found = true;
|
_alert = AlertState.Invalid;
|
||||||
hideAlert = false;
|
StateHasChanged();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
textField.Clear();
|
if (Secret == null)
|
||||||
|
await GenerateSecret.InvokeAsync();
|
||||||
|
|
||||||
|
if(await TestInput(Input))
|
||||||
|
{
|
||||||
|
_found = true;
|
||||||
|
_alert = AlertState.Correct;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _textField.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prüft ob die Eingabe korrekt ist.
|
/// Prüft ob die Eingabe korrekt ist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool TestInput(string input)
|
private async Task<bool> TestInput(string input)
|
||||||
{
|
{
|
||||||
CharData[] validatedInput = new CharData[ColumnCount];
|
CharData[] validatedInput = new CharData[ColumnCount];
|
||||||
|
|
||||||
|
@ -221,20 +217,19 @@
|
||||||
validatedInput[i] = new CharData(guessedChar, state);
|
validatedInput[i] = new CharData(guessedChar, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreviousGuesses.Add(validatedInput);
|
_previousGuesses.Add(validatedInput);
|
||||||
|
|
||||||
InputValidated?.Invoke(this, validatedInput);
|
await InputValidated.InvokeAsync(validatedInput);
|
||||||
|
|
||||||
return correct;
|
return correct;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlayAgain()
|
public async Task PlayAgain()
|
||||||
{
|
{
|
||||||
PreviousGuesses.Clear();
|
_previousGuesses.Clear();
|
||||||
hideAlert = true;
|
_alert = AlertState.None;
|
||||||
found = false;
|
_found = false;
|
||||||
|
|
||||||
if (GenerateSecret != null)
|
await GenerateSecret.InvokeAsync();
|
||||||
Secret = GenerateSecret();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
<!-- Matrix mit Buchstabenfeldern -->
|
||||||
<!-- Matrix mit Buchstabenfeldern -->
|
|
||||||
<div class="d-flex justify-center mt-2 mb-2">
|
<div class="d-flex justify-center mt-2 mb-2">
|
||||||
<div>
|
<div>
|
||||||
@{
|
@{
|
||||||
|
@ -14,27 +13,29 @@
|
||||||
|
|
||||||
char upperKey = char.ToUpper(key);
|
char upperKey = char.ToUpper(key);
|
||||||
|
|
||||||
if (_correctKeys.Contains(upperKey))
|
_knownKeyStates.TryGetValue(upperKey, out var keyState);
|
||||||
|
|
||||||
|
if (keyState == WordleComponent.CharState.Correct)
|
||||||
{
|
{
|
||||||
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Success" @onclick="() => ButtonPressed(key)">
|
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Success">
|
||||||
<MudText Typo="Typo.h5">@upperKey</MudText>
|
<MudText Typo="Typo.h5">@upperKey</MudText>
|
||||||
</MudButton>
|
</MudButton>
|
||||||
}
|
}
|
||||||
else if (_misplacedKeys.Contains(upperKey))
|
else if (keyState == WordleComponent.CharState.Misplaced)
|
||||||
{
|
{
|
||||||
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Warning" @onclick="() => ButtonPressed(key)">
|
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Warning">
|
||||||
<MudText Typo="Typo.h5">@upperKey</MudText>
|
<MudText Typo="Typo.h5">@upperKey</MudText>
|
||||||
</MudButton>
|
</MudButton>
|
||||||
}
|
}
|
||||||
else if (_wrongKeys.Contains(upperKey))
|
else if (keyState == WordleComponent.CharState.Wrong)
|
||||||
{
|
{
|
||||||
<MudButton Disabled="true" Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Error" @onclick="() => ButtonPressed(key)">
|
<MudButton Disabled="true" Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" Color="Color.Error">
|
||||||
<MudText Typo="Typo.h5">@upperKey</MudText>
|
<MudText Typo="Typo.h5">@upperKey</MudText>
|
||||||
</MudButton>
|
</MudButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em" @onclick="() => ButtonPressed(key)">
|
<MudButton Variant="Variant.Outlined" Class="mr-2" Style="width: 5em; height: 5em">
|
||||||
<MudText Typo="Typo.h5">@upperKey</MudText>
|
<MudText Typo="Typo.h5">@upperKey</MudText>
|
||||||
</MudButton>
|
</MudButton>
|
||||||
}
|
}
|
||||||
|
@ -50,11 +51,7 @@
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public char[] Keys { get; set; } = Array.Empty<char>();
|
public char[] Keys { get; set; } = Array.Empty<char>();
|
||||||
|
|
||||||
private List<char> _correctKeys = new();
|
private Dictionary<char, WordleComponent.CharState> _knownKeyStates = new();
|
||||||
|
|
||||||
private List<char> _misplacedKeys = new();
|
|
||||||
|
|
||||||
private List<char> _wrongKeys = new();
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int KeysPerRow { get; set; } = 10;
|
public int KeysPerRow { get; set; } = 10;
|
||||||
|
@ -69,4 +66,36 @@
|
||||||
{
|
{
|
||||||
await KeyPressed.InvokeAsync(c);
|
await KeyPressed.InvokeAsync(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateKeyInfo(WordleComponent.CharData cd)
|
||||||
|
{
|
||||||
|
_knownKeyStates.TryGetValue(cd.Char, out var oldState);
|
||||||
|
|
||||||
|
WordleComponent.CharState newState = WordleComponent.CharState.None;
|
||||||
|
|
||||||
|
switch (cd.State)
|
||||||
|
{
|
||||||
|
case WordleComponent.CharState.Correct:
|
||||||
|
newState = WordleComponent.CharState.Correct;
|
||||||
|
break;
|
||||||
|
case WordleComponent.CharState.Misplaced:
|
||||||
|
// Den besseren Zustand nicht durch schlechteren ersetzen
|
||||||
|
if (oldState != WordleComponent.CharState.Correct)
|
||||||
|
{
|
||||||
|
newState = WordleComponent.CharState.Misplaced;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WordleComponent.CharState.Wrong:
|
||||||
|
newState = WordleComponent.CharState.Wrong;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_knownKeyStates[cd.Char] = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetKeyInfo()
|
||||||
|
{
|
||||||
|
_knownKeyStates.Clear();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,4 +17,9 @@
|
||||||
<PackageReference Include="MudBlazor" Version="6.0.7" />
|
<PackageReference Include="MudBlazor" Version="6.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\DataAccess\DataAccess.csproj" />
|
||||||
|
<ProjectReference Include="..\GottfriedsNackenUtility\GottfriedsNackenUtility.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
@page "/databasetest"
|
||||||
|
|
||||||
|
@using DataAccess.Data
|
||||||
|
@using DataAccess.Models
|
||||||
|
@inject IUserData _userData
|
||||||
|
|
||||||
|
<PageTitle>Database Test</PageTitle>
|
||||||
|
|
||||||
|
<MudContainer MaxWidth="MaxWidth.Small">
|
||||||
|
<MudTable Items="@_users" Hover="true" Breakpoint="Breakpoint.Sm" Loading="_loading">
|
||||||
|
<ToolBarContent>
|
||||||
|
<MudText Typo="Typo.h6">Nutzer</MudText>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Refresh" OnClick="RefreshUserList" />
|
||||||
|
</ToolBarContent>
|
||||||
|
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>Id</MudTh>
|
||||||
|
<MudTh>First Name</MudTh>
|
||||||
|
<MudTh>Last Name</MudTh>
|
||||||
|
<MudTh/>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="Nr">@context.Id</MudTd>
|
||||||
|
<MudTd DataLabel="First Name">@context.FirstName</MudTd>
|
||||||
|
<MudTd DataLabel="Last Name">@context.LastName</MudTd>
|
||||||
|
<MudTd>
|
||||||
|
<MudIconButton Icon="@Icons.Material.Filled.Delete" OnClick="() => DeleteUser(context)" />
|
||||||
|
</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
|
||||||
|
<PagerContent>
|
||||||
|
<MudTablePager/>
|
||||||
|
</PagerContent>
|
||||||
|
</MudTable>
|
||||||
|
|
||||||
|
<MudPaper Class="pa-4 mt-2">
|
||||||
|
<MudForm @bind-IsValid="_newUserValid" >
|
||||||
|
|
||||||
|
<MudText Typo="Typo.h4">Neuen Nutzer erstellen:</MudText>
|
||||||
|
<MudTextField T="string" Label="Vorname" @bind-Value="_newUser.FirstName" Immediate="true" Required="true" RequiredError="Vorname muss angegeben werden!"/>
|
||||||
|
<MudTextField T="string" Label="Nachname" @bind-Value="_newUser.LastName" Immediate="true" Required="true" RequiredError="Nachname muss angegeben werden!"/>
|
||||||
|
<MudButton Class="mt-2" Variant="Variant.Filled" Color="Color.Primary" Disabled="!_newUserValid" OnClick="AddUser">Hinzufügen</MudButton>
|
||||||
|
</MudForm>
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
</MudContainer>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private bool _newUserValid;
|
||||||
|
|
||||||
|
private UserModel _newUser = new();
|
||||||
|
|
||||||
|
private bool _loading;
|
||||||
|
|
||||||
|
private IEnumerable<UserModel> _users = Enumerable.Empty<UserModel>();
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await RefreshUserList();
|
||||||
|
|
||||||
|
await base.OnInitializedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshUserList()
|
||||||
|
{
|
||||||
|
_loading = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_users = await _userData.GetUsers();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to load users. Exception: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddUser()
|
||||||
|
{
|
||||||
|
await _userData.InsertUser(_newUser);
|
||||||
|
|
||||||
|
await RefreshUserList();
|
||||||
|
|
||||||
|
_newUser = new UserModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteUser(UserModel user)
|
||||||
|
{
|
||||||
|
await _userData.DeleteUser(user.Id);
|
||||||
|
|
||||||
|
await RefreshUserList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +1,50 @@
|
||||||
@page "/numberle"
|
@page "/numberle"
|
||||||
|
|
||||||
@using GottfriedsNackenWebseite.Components
|
@using GottfriedsNackenWebseite.Components
|
||||||
@using System.Diagnostics
|
|
||||||
@using GottfriedsNackenWebseite.Numberle
|
@using GottfriedsNackenWebseite.Numberle
|
||||||
|
@using GottfriedsNackenUtility
|
||||||
|
@using System.Diagnostics
|
||||||
|
@using System.Numerics
|
||||||
|
|
||||||
<PageTitle>Nacken Numberle</PageTitle>
|
<PageTitle>Nacken Numberle</PageTitle>
|
||||||
<MudText Align="Align.Center" Class="mt-2 mb-2"> Gebe eine (korrekte) mathematische Gleichung ein:</MudText>
|
<MudText Align="Align.Center" Class="mt-2 mb-2"> Gebe eine (korrekte) mathematische Gleichung ein:</MudText>
|
||||||
|
|
||||||
<WordleComponent ColumnCount="8" GenerateSecret="GenerateSecret" InputMask="@_inputMask" CheckInput="CheckInput" @ref="_wordle" />
|
<WordleComponent ColumnCount="8" GenerateSecret="OnGenerateNewSecret" InputMask="@_inputMask" CheckInput="CheckInput" InputValidated="OnInputValidated" @ref="_wordle" />
|
||||||
|
|
||||||
<WordleKeyboardComponent KeyPressed="KeyboardKeyPressed" Keys="Chars" />
|
<WordleKeyboardComponent @ref="_keyboard" KeyPressed="KeyboardKeyPressed" Keys="Chars" />
|
||||||
|
|
||||||
|
<MudOverlay @bind-Visible="_showLoadingOverlay" DarkBackground="true">
|
||||||
|
<MudCard>
|
||||||
|
<MudCardHeader>
|
||||||
|
<MudText Typo="Typo.h5">Bitte warten...</MudText>
|
||||||
|
</MudCardHeader>
|
||||||
|
<MudCardContent>
|
||||||
|
<MudText>Erzeuge eine unknackbare Formel mit roher Gewalt!</MudText>
|
||||||
|
<MudProgressLinear Color="Color.Secondary" Indeterminate="_progress < 0" Value="_progress" Class="my-7"/>
|
||||||
|
</MudCardContent>
|
||||||
|
</MudCard>
|
||||||
|
</MudOverlay>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private IMask _inputMask = new RegexMask(@"^[0-9+\-*/=]{0,8}$");
|
private static readonly IMask _inputMask = new RegexMask(@"^[0-9+\-*/=]{0,8}$");
|
||||||
|
|
||||||
private Parser _parser = new();
|
private readonly Parser _parser = new();
|
||||||
|
|
||||||
private WordleComponent _wordle;
|
private WordleComponent _wordle = default!;
|
||||||
|
private WordleKeyboardComponent _keyboard = default!;
|
||||||
|
|
||||||
|
private bool _showLoadingOverlay;
|
||||||
|
private int _progress;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prüft ob input eine gültige Gleichung ist.
|
||||||
|
/// </summary>
|
||||||
private bool CheckInput(string input)
|
private bool CheckInput(string input)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -36,7 +57,7 @@
|
||||||
|
|
||||||
(decimal value, int equalSigns) = CrunchyValidaty(ast);
|
(decimal value, int equalSigns) = CrunchyValidaty(ast);
|
||||||
|
|
||||||
// Wir akzeptieren nur, wenn es exakt ein Gleichheitszeichen gibt und diese erfüllt ist.
|
// Wir akzeptieren nur, wenn es exakt ein Gleichheitszeichen gibt und die Gleichung erfüllt ist.
|
||||||
return value == 1 && equalSigns == 1;
|
return value == 1 && equalSigns == 1;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -84,12 +105,55 @@
|
||||||
return (0, 0);
|
return (0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Die Zeichen aus denen eine Antwort besteht.
|
||||||
|
/// </summary>
|
||||||
private static readonly char[] Chars = {
|
private static readonly char[] Chars = {
|
||||||
'=', '+', '-', '*', '/',
|
'=', '+', '-', '*', '/',
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
||||||
};
|
};
|
||||||
|
|
||||||
private string GenerateSecret()
|
/// <summary>
|
||||||
|
/// Generiert ein neues Geheimnis und zeigt während dessen den Ladebalken an.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task OnGenerateNewSecret()
|
||||||
|
{
|
||||||
|
_keyboard.ResetKeyInfo();
|
||||||
|
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
Task? amazingTask = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Ladebalkenaktualisierer starten
|
||||||
|
amazingTask = SusHelper.UpdateDefinitelyNotFakeProgress(progress =>
|
||||||
|
{
|
||||||
|
_progress = progress;
|
||||||
|
StateHasChanged();
|
||||||
|
}, cts.Token);
|
||||||
|
|
||||||
|
_showLoadingOverlay = true;
|
||||||
|
|
||||||
|
_wordle.Secret = await Task.Run(GenerateFormula);
|
||||||
|
|
||||||
|
_showLoadingOverlay = false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Ladebalkenaktualisierer stoppen
|
||||||
|
cts.Cancel();
|
||||||
|
if (amazingTask != null)
|
||||||
|
await amazingTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erzeugt eine neue (gültige) Formel.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Die Formel</returns>
|
||||||
|
private string GenerateFormula()
|
||||||
{
|
{
|
||||||
int charCount = 8;
|
int charCount = 8;
|
||||||
|
|
||||||
|
@ -99,6 +163,8 @@
|
||||||
int equalsIndex = Random.Shared.Next(1, charCount - 1);
|
int equalsIndex = Random.Shared.Next(1, charCount - 1);
|
||||||
formula[equalsIndex] = '=';
|
formula[equalsIndex] = '=';
|
||||||
|
|
||||||
|
// Ersetzt das Zeichen mit Index "index" durch einen Zufälligen wert.
|
||||||
|
// TODO: ein etwas gewiefterer Algorithmus würde nicht schaden.
|
||||||
void PlaceRandomChar(int index)
|
void PlaceRandomChar(int index)
|
||||||
{
|
{
|
||||||
char left = (index > 0) ? formula[index - 1] : '\0';
|
char left = (index > 0) ? formula[index - 1] : '\0';
|
||||||
|
@ -127,13 +193,26 @@
|
||||||
Debug.WriteLine(str);
|
Debug.WriteLine(str);
|
||||||
|
|
||||||
if (CheckInput(str))
|
if (CheckInput(str))
|
||||||
|
{
|
||||||
return str;
|
return str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task KeyboardKeyPressed(char key)
|
private async Task KeyboardKeyPressed(char key)
|
||||||
{
|
{
|
||||||
await _wordle.SetText(_wordle.Input + key); //Input += key;
|
// TODO: Virtuelles Keyboard
|
||||||
|
//await _wordle.SetText(_wordle.Input + key); //Input += key;
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInputValidated(WordleComponent.CharData[] data)
|
||||||
|
{
|
||||||
|
// Auswertung in das Keyboard packen
|
||||||
|
foreach (WordleComponent.CharData cd in data)
|
||||||
|
{
|
||||||
|
_keyboard.UpdateKeyInfo(cd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
using DataAccess.Data;
|
||||||
|
using DataAccess.DbAccess;
|
||||||
using GottfriedsNackenWebseite.Data;
|
using GottfriedsNackenWebseite.Data;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
@ -11,6 +13,9 @@ builder.Services.AddServerSideBlazor();
|
||||||
builder.Services.AddSingleton<WeatherForecastService>();
|
builder.Services.AddSingleton<WeatherForecastService>();
|
||||||
builder.Services.AddMudServices();
|
builder.Services.AddMudServices();
|
||||||
|
|
||||||
|
builder.Services.AddSingleton<ISqlDataAccess, SqlDataAccess>();
|
||||||
|
builder.Services.AddSingleton<IUserData, UserData>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
<MudNavLink Href="numberle" Match=NavLinkMatch.Prefix>
|
<MudNavLink Href="numberle" Match=NavLinkMatch.Prefix>
|
||||||
Nacken Numberle
|
Nacken Numberle
|
||||||
</MudNavLink>
|
</MudNavLink>
|
||||||
|
<MudNavLink Href="databasetest" Match=NavLinkMatch.Prefix>
|
||||||
|
Datenbank Test
|
||||||
|
</MudNavLink>
|
||||||
</MudNavMenu>
|
</MudNavMenu>
|
||||||
@*
|
@*
|
||||||
<div class="top-row ps-3 navbar navbar-dark">
|
<div class="top-row ps-3 navbar navbar-dark">
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"DetailedErrors": true,
|
"DetailedErrors": true,
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"Default": "PLACEHOLDER"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue