diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index e3d3afe..738674d 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -80,7 +80,7 @@ public partial class Annotator Loaded += OnLoaded; Closed += OnFormClosed; - + Activated += (_, _) => _formState.ActiveWindow = WindowEnum.Annotator; Editor.GetTimeFunc = () => TimeSpan.FromMilliseconds(_mediaPlayer.Time); } diff --git a/Azaion.Annotator/Extensions/VLCFrameExtractor.cs b/Azaion.Annotator/Extensions/VLCFrameExtractor.cs index c415a5e..7c52943 100644 --- a/Azaion.Annotator/Extensions/VLCFrameExtractor.cs +++ b/Azaion.Annotator/Extensions/VLCFrameExtractor.cs @@ -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 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)); diff --git a/Azaion.Common/Azaion.Common.csproj b/Azaion.Common/Azaion.Common.csproj index b7bdd7e..04c0f62 100644 --- a/Azaion.Common/Azaion.Common.csproj +++ b/Azaion.Common/Azaion.Common.csproj @@ -7,12 +7,12 @@ - + diff --git a/Azaion.Common/Constants.cs b/Azaion.Common/Constants.cs index 0d50595..cf99f65 100644 --- a/Azaion.Common/Constants.cs +++ b/Azaion.Common/Constants.cs @@ -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 diff --git a/Azaion.Annotator/DTO/AnnotationResult.cs b/Azaion.Common/DTO/AnnotationResult.cs similarity index 93% rename from Azaion.Annotator/DTO/AnnotationResult.cs rename to Azaion.Common/DTO/AnnotationResult.cs index dff2929..94a89e4 100644 --- a/Azaion.Annotator/DTO/AnnotationResult.cs +++ b/Azaion.Common/DTO/AnnotationResult.cs @@ -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 { diff --git a/Azaion.Common/DTO/ApiCredentials.cs b/Azaion.Common/DTO/ApiCredentials.cs index 2761ede..493b310 100644 --- a/Azaion.Common/DTO/ApiCredentials.cs +++ b/Azaion.Common/DTO/ApiCredentials.cs @@ -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; } \ No newline at end of file diff --git a/Azaion.Annotator/DTO/FormState.cs b/Azaion.Common/DTO/FormState.cs similarity index 90% rename from Azaion.Annotator/DTO/FormState.cs rename to Azaion.Common/DTO/FormState.cs index 1936225..a6dcf7d 100644 --- a/Azaion.Annotator/DTO/FormState.cs +++ b/Azaion.Common/DTO/FormState.cs @@ -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 AnnotationResults { get; set; } = []; + public WindowEnum ActiveWindow { get; set; } public string GetTimeName(TimeSpan? ts) => $"{VideoName}_{ts:hmmssf}"; } \ No newline at end of file diff --git a/Azaion.Annotator/DTO/MediaFileInfo.cs b/Azaion.Common/DTO/MediaFileInfo.cs similarity index 91% rename from Azaion.Annotator/DTO/MediaFileInfo.cs rename to Azaion.Common/DTO/MediaFileInfo.cs index 3ba625d..fcaf6bc 100644 --- a/Azaion.Annotator/DTO/MediaFileInfo.cs +++ b/Azaion.Common/DTO/MediaFileInfo.cs @@ -1,4 +1,4 @@ -namespace Azaion.Annotator.DTO; +namespace Azaion.Common.DTO; public class MediaFileInfo { diff --git a/Azaion.Annotator/DTO/MediaTypes.cs b/Azaion.Common/DTO/MediaTypes.cs similarity index 66% rename from Azaion.Annotator/DTO/MediaTypes.cs rename to Azaion.Common/DTO/MediaTypes.cs index d5c5ede..fadb806 100644 --- a/Azaion.Annotator/DTO/MediaTypes.cs +++ b/Azaion.Common/DTO/MediaTypes.cs @@ -1,4 +1,4 @@ -namespace Azaion.Annotator.DTO; +namespace Azaion.Common.DTO; public enum MediaTypes { diff --git a/Azaion.Common/DTO/RoleEnum.cs b/Azaion.Common/DTO/RoleEnum.cs new file mode 100644 index 0000000..3eac6d8 --- /dev/null +++ b/Azaion.Common/DTO/RoleEnum.cs @@ -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 +} diff --git a/Azaion.Common/DTO/User.cs b/Azaion.Common/DTO/User.cs new file mode 100644 index 0000000..2d9b90a --- /dev/null +++ b/Azaion.Common/DTO/User.cs @@ -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 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; + } +} \ No newline at end of file diff --git a/Azaion.Common/Services/AzaionApiClient.cs b/Azaion.Common/Services/AzaionApiClient.cs index c1a02cf..28f352f 100644 --- a/Azaion.Common/Services/AzaionApiClient.cs +++ b/Azaion.Common/Services/AzaionApiClient.cs @@ -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 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 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); } @@ -88,4 +95,4 @@ public class AzaionApiClient(HttpClient httpClient) : IDisposable httpClient.Dispose(); Password.Dispose(); } -} +} \ No newline at end of file diff --git a/Azaion.Common/Services/HardwareService.cs b/Azaion.Common/Services/HardwareService.cs index 2e6de21..d03e78f 100644 --- a/Azaion.Common/Services/HardwareService.cs +++ b/Azaion.Common/Services/HardwareService.cs @@ -8,7 +8,7 @@ namespace Azaion.Common.Services; public interface IHardwareService { - Task 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 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 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(); } diff --git a/Azaion.Common/Services/ResourceLoader.cs b/Azaion.Common/Services/ResourceLoader.cs index 0832521..c180ccc 100644 --- a/Azaion.Common/Services/ResourceLoader.cs +++ b/Azaion.Common/Services/ResourceLoader.cs @@ -46,8 +46,9 @@ public class ResourceLoader(AzaionApiClient api, ApiCredentials credentials) : I public async Task 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(); diff --git a/Azaion.Dataset/DatasetExplorer.xaml.cs b/Azaion.Dataset/DatasetExplorer.xaml.cs index da37c08..ea24eb8 100644 --- a/Azaion.Dataset/DatasetExplorer.xaml.cs +++ b/Azaion.Dataset/DatasetExplorer.xaml.cs @@ -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,60 +34,17 @@ public partial class DatasetExplorer IOptions directoriesConfig, IOptions annotationConfig, ILogger logger, - IGalleryManager galleryManager) + IGalleryManager galleryManager, + FormState formState) { _directoriesConfig = directoriesConfig.Value; _annotationConfig = annotationConfig.Value; _logger = logger; _galleryManager = galleryManager; + _formState = formState; InitializeComponent(); - Loaded += async (_, _) => - { - _ = Task.Run(async () => await _galleryManager.RefreshThumbnails()); - - AllAnnotationClasses = new ObservableCollection( - new List { new() {Id = -1, Name = "All", ShortName = "All"}} - .Concat(_annotationConfig.AnnotationClasses)); - LvClasses.ItemsSource = AllAnnotationClasses; - - LvClasses.MouseUp += async (_, _) => - { - var selectedClass = (AnnotationClass)LvClasses.SelectedItem; - ExplorerEditor.CurrentAnnClass = selectedClass; - _annotationConfig.LastSelectedExplorerClass = selectedClass.Id; - - if (Switcher.SelectedIndex == 0) - await ReloadThumbnails(); - else - foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected)) - ann.AnnotationClass = selectedClass; - }; - - LvClasses.SelectionChanged += (_, _) => - { - if (Switcher.SelectedIndex != 1) - return; - - var selectedClass = (AnnotationClass)LvClasses.SelectedItem; - if (selectedClass == null) - return; - - ExplorerEditor.CurrentAnnClass = selectedClass; - - foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected)) - ann.AnnotationClass = selectedClass; - }; - - - LvClasses.SelectedIndex = _annotationConfig.LastSelectedExplorerClass ?? 0; - ExplorerEditor.CurrentAnnClass = (AnnotationClass)LvClasses.SelectedItem; - await ReloadThumbnails(); - LoadClassDistribution(); - - RefreshThumbBar.Value = galleryManager.ThumbnailsPercentage; - DataContext = this; - }; + Loaded += OnLoaded; ThumbnailsView.KeyDown += async (sender, args) => { @@ -115,6 +73,53 @@ public partial class DatasetExplorer } + private async void OnLoaded(object sender, RoutedEventArgs e) + { + _ = Task.Run(async () => await _galleryManager.RefreshThumbnails()); + + AllAnnotationClasses = new ObservableCollection( + new List { new() {Id = -1, Name = "All", ShortName = "All"}} + .Concat(_annotationConfig.AnnotationClasses)); + LvClasses.ItemsSource = AllAnnotationClasses; + + LvClasses.MouseUp += async (_, _) => + { + var selectedClass = (AnnotationClass)LvClasses.SelectedItem; + ExplorerEditor.CurrentAnnClass = selectedClass; + _annotationConfig.LastSelectedExplorerClass = selectedClass.Id; + + if (Switcher.SelectedIndex == 0) + await ReloadThumbnails(); + else + foreach (var ann in ExplorerEditor.CurrentAnns.Where(x => x.IsSelected)) + ann.AnnotationClass = selectedClass; + }; + + LvClasses.SelectionChanged += (_, _) => + { + if (Switcher.SelectedIndex != 1) + return; + + var selectedClass = (AnnotationClass)LvClasses.SelectedItem; + if (selectedClass == null) + return; + + ExplorerEditor.CurrentAnnClass = selectedClass; + + 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; + DataContext = this; + } + private void LoadClassDistribution() { var data = _galleryManager.LabelsCache diff --git a/Azaion.Launcher/App.xaml b/Azaion.Launcher/App.xaml deleted file mode 100644 index 1af3995..0000000 --- a/Azaion.Launcher/App.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - diff --git a/Azaion.Launcher/App.xaml.cs b/Azaion.Launcher/App.xaml.cs deleted file mode 100644 index d26963a..0000000 --- a/Azaion.Launcher/App.xaml.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Azaion.Launcher; - -public partial class App; \ No newline at end of file diff --git a/Azaion.Launcher/AssemblyInfo.cs b/Azaion.Launcher/AssemblyInfo.cs deleted file mode 100644 index 4a05c7d..0000000 --- a/Azaion.Launcher/AssemblyInfo.cs +++ /dev/null @@ -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) -)] \ No newline at end of file diff --git a/Azaion.Launcher/Azaion.Launcher.csproj b/Azaion.Launcher/Azaion.Launcher.csproj deleted file mode 100644 index b2660a7..0000000 --- a/Azaion.Launcher/Azaion.Launcher.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - WinExe - net8.0-windows - enable - enable - true - - - - - MSBuild:Compile - Wpf - Designer - - - - diff --git a/Azaion.Suite.sln b/Azaion.Suite.sln index 0f03c37..3cc2933 100644 --- a/Azaion.Suite.sln +++ b/Azaion.Suite.sln @@ -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 diff --git a/Azaion.Suite/App.xaml.cs b/Azaion.Suite/App.xaml.cs index ce9a429..f3b6fd4 100644 --- a/Azaion.Suite/App.xaml.cs +++ b/Azaion.Suite/App.xaml.cs @@ -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 _logger; - private readonly IMediator _mediator; + private IHost _host = null!; + private ILogger _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(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().Show(); + }; + + login.ShowDialog(); + } + + private void StartMain() { Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() @@ -97,7 +116,9 @@ public partial class App { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(ResourceLoader); + + services.AddSingleton(_apiClient); + services.AddSingleton(_resourceLoader); services.Configure(context.Configuration); services.ConfigureSection(context.Configuration); @@ -141,31 +162,15 @@ public partial class App .Build(); _mediator = _host.Services.GetRequiredService(); _logger = _host.Services.GetRequiredService>(); + _formState = _host.Services.GetRequiredService(); 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().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(); } } \ No newline at end of file diff --git a/Azaion.Suite/Azaion.Suite.csproj b/Azaion.Suite/Azaion.Suite.csproj index 6d11ed8..cd6667d 100644 --- a/Azaion.Suite/Azaion.Suite.csproj +++ b/Azaion.Suite/Azaion.Suite.csproj @@ -10,7 +10,6 @@ - @@ -40,6 +39,14 @@ + + + MSBuild:Compile + Wpf + Designer + + + diff --git a/Azaion.Launcher/Loader.xaml b/Azaion.Suite/Login.xaml similarity index 98% rename from Azaion.Launcher/Loader.xaml rename to Azaion.Suite/Login.xaml index 9f17f8b..0978c07 100644 --- a/Azaion.Launcher/Loader.xaml +++ b/Azaion.Suite/Login.xaml @@ -1,4 +1,4 @@ - + Click="LoginClick">