rework to have only 1 exe!

This commit is contained in:
Alex Bezdieniezhnykh
2024-12-04 20:51:26 +02:00
parent 3944df8efe
commit 60519461a1
25 changed files with 194 additions and 198 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ public partial class Annotator
Loaded += OnLoaded;
Closed += OnFormClosed;
Activated += (_, _) => _formState.ActiveWindow = WindowEnum.Annotator;
Editor.GetTimeFunc = () => TimeSpan.FromMilliseconds(_mediaPlayer.Time);
}
@@ -4,11 +4,12 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Azaion.Common.DTO.Config;
using LibVLCSharp.Shared;
using Microsoft.Extensions.Options;
using SkiaSharp;
namespace Azaion.Annotator.Extensions;
public class VLCFrameExtractor(LibVLC libVLC, AIRecognitionConfig config)
public class VLCFrameExtractor(LibVLC libVLC, IOptions<AIRecognitionConfig> config)
{
private const uint RGBA_BYTES = 4;
private const int PLAYBACK_RATE = 4;
@@ -105,7 +106,7 @@ public class VLCFrameExtractor(LibVLC libVLC, AIRecognitionConfig config)
_lastFrameTimestamp = playerTime;
}
if (_frameCounter > 20 && _frameCounter % config.FramePeriodRecognition == 0)
if (_frameCounter > 20 && _frameCounter % config.Value.FramePeriodRecognition == 0)
{
var msToAdd = (_frameCounter - _lastFrame) * (_lastFrame == 0 ? 0 : _lastFrameTimestamp.TotalMilliseconds / _lastFrame);
var time = _lastFrameTimestamp.Add(TimeSpan.FromMilliseconds(msToAdd));
+1 -1
View File
@@ -7,12 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" />
</ItemGroup>
</Project>
+5
View File
@@ -13,6 +13,11 @@ public class Constants
public const string DEFAULT_API_URL = "https://api.azaion.com/";
public const int DEFAULT_API_RETRY_COUNT = 3;
public const int DEFAULT_API_TIMEOUT_SECONDS = 40;
public const string CLAIM_NAME_ID = "nameid";
public const string CLAIM_EMAIL = "unique_name";
public const string CLAIM_ROLE = "role";
#endregion ApiConfig
#region DirectoriesConfig
@@ -1,8 +1,7 @@
using System.Windows.Media;
using Azaion.Common.DTO;
using Newtonsoft.Json;
namespace Azaion.Annotator.DTO;
namespace Azaion.Common.DTO;
public class AnnotationResult
{
+4 -9
View File
@@ -1,12 +1,7 @@
using CommandLine;
namespace Azaion.Common.DTO;
namespace Azaion.Common.DTO;
public class ApiCredentials
public class ApiCredentials(string email, string password) : EventArgs
{
[Option('e', "email", Required = true, HelpText = "The email for authorization.")]
public string Email { get; set; } = null!;
[Option('p', "password", Required = true, HelpText = "The password for authorization.")]
public string Password { get; set; } = null!;
public string Email { get; set; } = email;
public string Password { get; set; } = password;
}
@@ -2,7 +2,7 @@
using System.IO;
using System.Windows;
namespace Azaion.Annotator.DTO;
namespace Azaion.Common.DTO;
public class FormState
{
@@ -18,6 +18,7 @@ public class FormState
public TimeSpan? BackgroundTime { get; set; }
public int CurrentVolume { get; set; } = 100;
public ObservableCollection<AnnotationResult> AnnotationResults { get; set; } = [];
public WindowEnum ActiveWindow { get; set; }
public string GetTimeName(TimeSpan? ts) => $"{VideoName}_{ts:hmmssf}";
}
@@ -1,4 +1,4 @@
namespace Azaion.Annotator.DTO;
namespace Azaion.Common.DTO;
public class MediaFileInfo
{
@@ -1,4 +1,4 @@
namespace Azaion.Annotator.DTO;
namespace Azaion.Common.DTO;
public enum MediaTypes
{
+12
View File
@@ -0,0 +1,12 @@
namespace Azaion.Common.DTO;
public enum RoleEnum
{
None = 0,
Operator = 10, //only annotator is available. Could send annotations to queue.
Validator = 20, //annotator + dataset explorer. This role allows to receive annotations from the queue.
CompanionPC = 30,
Admin = 40, //
ResourceUploader = 50, //Uploading dll and ai models
ApiAdmin = 1000 //everything
}
+21
View File
@@ -0,0 +1,21 @@
using System.Security.Claims;
namespace Azaion.Common.DTO;
public class User
{
public Guid Id { get; set; }
public string Email { get; set; }
public RoleEnum Role { get; set; }
public User(IEnumerable<Claim> claims)
{
var claimDict = claims.ToDictionary(x => x.Type, x => x.Value);
Id = Guid.Parse(claimDict[Constants.CLAIM_NAME_ID]);
Email = claimDict[Constants.CLAIM_EMAIL];
if (!Enum.TryParse(claimDict[Constants.CLAIM_ROLE], out RoleEnum role))
role = RoleEnum.None;
Role = role;
}
}
+11 -4
View File
@@ -6,6 +6,7 @@ using System.Security;
using System.Text;
using Azaion.Common.DTO;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
namespace Azaion.Common.Services;
@@ -15,7 +16,9 @@ public class AzaionApiClient(HttpClient httpClient) : IDisposable
private string Email { get; set; } = null!;
private SecureString Password { get; set; } = new();
private string JwtToken { get; set; } = null!;
public User User { get; set; } = null!;
public void EnterCredentials(ApiCredentials credentials)
{
@@ -35,7 +38,7 @@ public class AzaionApiClient(HttpClient httpClient) : IDisposable
return await response.Content.ReadAsStreamAsync();
}
private async Task<string> Authorize()
private async Task Authorize()
{
if (string.IsNullOrEmpty(Email) || Password.Length == 0)
throw new Exception("Email or password is empty! Please do EnterCredentials first!");
@@ -59,19 +62,23 @@ public class AzaionApiClient(HttpClient httpClient) : IDisposable
if (string.IsNullOrEmpty(result?.Token))
throw new Exception("JWT Token not found in response");
return result.Token;
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(result.Token);
User = new User(token.Claims);
JwtToken = result.Token;
}
private async Task<HttpResponseMessage> Send(HttpClient client, HttpRequestMessage request)
{
if (string.IsNullOrEmpty(JwtToken))
JwtToken = await Authorize();
await Authorize();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
var response = await client.SendAsync(request);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
JwtToken = await Authorize();
await Authorize();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", JwtToken);
response = await client.SendAsync(request);
}
+6 -6
View File
@@ -8,7 +8,7 @@ namespace Azaion.Common.Services;
public interface IHardwareService
{
Task<HardwareInfo> GetHardware();
HardwareInfo GetHardware();
}
public class HardwareService : IHardwareService
@@ -23,11 +23,11 @@ public class HardwareService : IHardwareService
"lscpu | grep 'Model name:' | cut -d':' -f2 && " +
"lspci | grep VGA | cut -d':' -f3\"";
public async Task<HardwareInfo> GetHardware()
public HardwareInfo GetHardware()
{
try
{
var output = await RunCommand(Environment.OSVersion.Platform == PlatformID.Win32NT
var output = RunCommand(Environment.OSVersion.Platform == PlatformID.Win32NT
? WIN32_GET_HARDWARE_COMMAND
: UNIX_GET_HARDWARE_COMMAND);
@@ -77,7 +77,7 @@ public class HardwareService : IHardwareService
return macAddress ?? string.Empty;
}
private async Task<string> RunCommand(string command)
private string RunCommand(string command)
{
try
{
@@ -91,8 +91,8 @@ public class HardwareService : IHardwareService
process.StartInfo.CreateNoWindow = true;
process.Start();
var result = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
var result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return result.Trim();
}
+3 -2
View File
@@ -46,8 +46,9 @@ public class ResourceLoader(AzaionApiClient api, ApiCredentials credentials) : I
public async Task<MemoryStream> Load(string fileName, CancellationToken cancellationToken = default)
{
var hardwareService = new HardwareService();
var hardwareInfo = await hardwareService.GetHardware();
var encryptedStream = await api.GetResource(fileName, credentials.Password, hardwareInfo);
var hardwareInfo = hardwareService.GetHardware();
var encryptedStream = Task.Run(() => api.GetResource(fileName, credentials.Password, hardwareInfo), cancellationToken).Result;
var key = Security.MakeEncryptionKey(credentials.Email, credentials.Password, hardwareInfo.Hash);
var stream = new MemoryStream();
+36 -31
View File
@@ -24,6 +24,7 @@ public partial class DatasetExplorer
private int _tempSelectedClassIdx = 0;
private readonly IGalleryManager _galleryManager;
private readonly FormState _formState;
public bool ThumbnailLoading { get; set; }
@@ -33,15 +34,46 @@ public partial class DatasetExplorer
IOptions<DirectoriesConfig> directoriesConfig,
IOptions<AnnotationConfig> annotationConfig,
ILogger<DatasetExplorer> logger,
IGalleryManager galleryManager)
IGalleryManager galleryManager,
FormState formState)
{
_directoriesConfig = directoriesConfig.Value;
_annotationConfig = annotationConfig.Value;
_logger = logger;
_galleryManager = galleryManager;
_formState = formState;
InitializeComponent();
Loaded += async (_, _) =>
Loaded += OnLoaded;
ThumbnailsView.KeyDown += async (sender, args) =>
{
switch (args.Key)
{
case Key.Delete:
DeleteAnnotations();
break;
case Key.Enter:
await EditAnnotation();
break;
}
};
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation();
ThumbnailsView.SelectionChanged += (_, _) =>
{
StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {ThumbnailsDtos.Count}";
};
ExplorerEditor.GetTimeFunc = () => Constants.GetTime(CurrentThumbnail!.ImagePath);
galleryManager.ThumbnailsUpdate += thumbnailsPercentage =>
{
Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage);
};
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
_ = Task.Run(async () => await _galleryManager.RefreshThumbnails());
@@ -77,42 +109,15 @@ public partial class DatasetExplorer
foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected))
ann.AnnotationClass = selectedClass;
};
Activated += (_, _) => _formState.ActiveWindow = WindowEnum.Annotator;
LvClasses.SelectedIndex = _annotationConfig.LastSelectedExplorerClass ?? 0;
ExplorerEditor.CurrentAnnClass = (AnnotationClass)LvClasses.SelectedItem;
await ReloadThumbnails();
LoadClassDistribution();
RefreshThumbBar.Value = galleryManager.ThumbnailsPercentage;
RefreshThumbBar.Value = _galleryManager.ThumbnailsPercentage;
DataContext = this;
};
ThumbnailsView.KeyDown += async (sender, args) =>
{
switch (args.Key)
{
case Key.Delete:
DeleteAnnotations();
break;
case Key.Enter:
await EditAnnotation();
break;
}
};
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation();
ThumbnailsView.SelectionChanged += (_, _) =>
{
StatusText.Text = $"Обрано: {ThumbnailsView.SelectedItems.Count} | {ThumbnailsView.SelectedIndex} / {ThumbnailsDtos.Count}";
};
ExplorerEditor.GetTimeFunc = () => Constants.GetTime(CurrentThumbnail!.ImagePath);
galleryManager.ThumbnailsUpdate += thumbnailsPercentage =>
{
Dispatcher.Invoke(() => RefreshThumbBar.Value = thumbnailsPercentage);
};
}
private void LoadClassDistribution()
-8
View File
@@ -1,8 +0,0 @@
<Application x:Class="Azaion.Launcher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Loader.xaml">
<Application.Resources>
</Application.Resources>
</Application>
-3
View File
@@ -1,3 +0,0 @@
namespace Azaion.Launcher;
public partial class App;
-10
View File
@@ -1,10 +0,0 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
-19
View File
@@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<Page Update="Loader.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
</Project>
-6
View File
@@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Common", "Azaion.Com
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Dataset", "Azaion.Dataset\Azaion.Dataset.csproj", "{01A5CA37-A62E-4EF3-8678-D72CD9525677}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azaion.Launcher", "Azaion.Launcher\Azaion.Launcher.csproj", "{00CC9AFE-2952-4943-BCBA-976AE03DE841}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dummy", "Dummy", "{C307BE2E-FFCC-4BD7-AD89-C82D40B65D03}"
ProjectSection(SolutionItems) = preProject
Dummy\Azaion.Annotator.dll = Dummy\Azaion.Annotator.dll
@@ -48,10 +46,6 @@ Global
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01A5CA37-A62E-4EF3-8678-D72CD9525677}.Release|Any CPU.Build.0 = Release|Any CPU
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Release|Any CPU.ActiveCfg = Release|Any CPU
{00CC9AFE-2952-4943-BCBA-976AE03DE841}.Release|Any CPU.Build.0 = Release|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32C4747F-F700-44FD-B4ED-21B4A66B5FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+48 -61
View File
@@ -1,10 +1,8 @@
using System.IO;
using System.Net.Http;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Azaion.Annotator;
using Azaion.Annotator.DTO;
using Azaion.Annotator.Extensions;
using Azaion.Common;
using Azaion.Common.DTO;
@@ -12,7 +10,6 @@ using Azaion.Common.DTO.Config;
using Azaion.Common.Extensions;
using Azaion.Common.Services;
using Azaion.Dataset;
using CommandLine;
using LibVLCSharp.Shared;
using MediatR;
using Microsoft.Extensions.Configuration;
@@ -22,31 +19,19 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Serilog;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
namespace Azaion.Suite;
public partial class App
{
private readonly IHost _host;
private readonly ILogger<App> _logger;
private readonly IMediator _mediator;
private IHost _host = null!;
private ILogger<App> _logger = null!;
private IMediator _mediator = null!;
private FormState _formState = null!;
//Authorize to api and
private static readonly IResourceLoader ResourceLoader;
static App()
{
new ConfigUpdater().CheckConfig();
var result = Parser.Default.ParseArguments<ApiCredentials>(Environment.GetCommandLineArgs());
var apiCreds = !result.Errors.Any()
? result.Value
: new ApiCredentials();
ResourceLoader = new ResourceLoader(CreateApiClient(apiCreds), apiCreds);
AppDomain.CurrentDomain.AssemblyResolve += (_, args) => ResourceLoader.LoadAssembly(args.Name);
}
private AzaionApiClient _apiClient = null!;
private IResourceLoader _resourceLoader = null!;
private static AzaionApiClient CreateApiClient(ApiCredentials credentials)
{
@@ -68,6 +53,7 @@ public partial class App
TimeoutSeconds = 40
};
}
var api = new AzaionApiClient(new HttpClient
{
BaseAddress = new Uri(apiConfig.Url),
@@ -78,7 +64,40 @@ public partial class App
return api;
}
public App()
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
_logger.LogError(e.Exception, e.Exception.Message);
e.Handled = true;
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
StartLogin();
}
private void StartLogin()
{
new ConfigUpdater().CheckConfig();
var login = new Login();
login.CredentialsEntered += async (s, args) =>
{
_apiClient = CreateApiClient(args);
_resourceLoader = new ResourceLoader(_apiClient, args);
AppDomain.CurrentDomain.AssemblyResolve += (_, a) => _resourceLoader.LoadAssembly(a.Name);
StartMain();
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
await _host.StartAsync();
_host.Services.GetRequiredService<MainSuite>().Show();
};
login.ShowDialog();
}
private void StartMain()
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
@@ -97,7 +116,9 @@ public partial class App
{
services.AddSingleton<MainSuite>();
services.AddSingleton<IHardwareService, HardwareService>();
services.AddSingleton(ResourceLoader);
services.AddSingleton(_apiClient);
services.AddSingleton(_resourceLoader);
services.Configure<AppConfig>(context.Configuration);
services.ConfigureSection<ApiConfig>(context.Configuration);
@@ -141,31 +162,15 @@ public partial class App
.Build();
_mediator = _host.Services.GetRequiredService<IMediator>();
_logger = _host.Services.GetRequiredService<ILogger<App>>();
_formState = _host.Services.GetRequiredService<FormState>();
DispatcherUnhandledException += OnDispatcherUnhandledException;
}
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
_logger.LogError(e.Exception, e.Exception.Message);
e.Handled = true;
}
protected override async void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(UIElement), UIElement.KeyDownEvent, new RoutedEventHandler(GlobalClick));
await _host.StartAsync();
_host.Services.GetRequiredService<MainSuite>().Show();
base.OnStartup(e);
}
private void GlobalClick(object sender, RoutedEventArgs e)
{
var args = (KeyEventArgs)e;
var windowEnum = GetParentWindow(sender as FrameworkElement);
if (windowEnum == WindowEnum.None)
return;
var keyEvent = new KeyEvent(sender, args, windowEnum);
var keyEvent = new KeyEvent(sender, args, _formState.ActiveWindow);
_ = ThrottleExt.Throttle(() => _mediator.Publish(keyEvent), TimeSpan.FromMilliseconds(50));
}
@@ -176,27 +181,9 @@ public partial class App
{ "Azaion.Dataset.DatasetExplorer", WindowEnum.DatasetExplorer }
};
private WindowEnum GetParentWindow(FrameworkElement? element)
{
while (element != null)
{
var windowEnum = _uiElementToWindowEnum!.GetValueOrDefault(element.GetType().FullName);
if (windowEnum != WindowEnum.None)
return windowEnum;
element = (element.Parent ?? element.TemplatedParent) as FrameworkElement;
}
return WindowEnum.None;
}
protected override async void OnExit(ExitEventArgs e)
{
base.OnExit(e);
await _host.StopAsync();
//_host.Dispose();
}
}
+8 -1
View File
@@ -10,7 +10,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="LibVLCSharp" Version="3.9.1" />
<PackageReference Include="LibVLCSharp.WPF" Version="3.9.1" />
<PackageReference Include="MediatR" Version="12.4.1" />
@@ -40,6 +39,14 @@
</Content>
</ItemGroup>
<ItemGroup>
<Page Update="Login.xaml">
<Generator>MSBuild:Compile</Generator>
<XamlRuntime>Wpf</XamlRuntime>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Target Name="PostBuild" AfterTargets="Build">
<MakeDir Directories="$(TargetDir)secure" />
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)secure" />
@@ -1,4 +1,4 @@
<Window x:Class="Azaion.Launcher.Loader"
<Window x:Class="Azaion.Suite.Login"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -97,7 +97,7 @@
Height="35"
Width="280"
Cursor="Hand"
Click="RunClick">
Click="LoginClick">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
@@ -1,21 +1,22 @@
using System.Diagnostics;
using System.Windows;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Azaion.Common.DTO;
namespace Azaion.Launcher;
namespace Azaion.Suite;
public partial class Loader : Window
public partial class Login
{
public Loader()
public Login()
{
InitializeComponent();
}
private async void RunClick(object sender, RoutedEventArgs e)
public event EventHandler<ApiCredentials>? CredentialsEntered;
private void LoginClick(object sender, RoutedEventArgs e)
{
Process.Start("Azaion.Suite.exe", $"-e {TbEmail.Text} -p {TbPassword.Password}");
await Task.Delay(2000);
CredentialsEntered?.Invoke(this, new ApiCredentials(TbEmail.Text, TbPassword.Password));
Close();
}
+2 -2
View File
@@ -6,10 +6,10 @@ namespace Azaion.Annotator.Test;
public class HardwareServiceTest
{
[Fact]
public async Task GetHardware_Test()
public void GetHardware_Test()
{
var hardwareService = new HardwareService();
var hw = await hardwareService.GetHardware();
var hw = hardwareService.GetHardware();
Console.WriteLine(hw);
}
}