diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5cb08dec2..cc5dcd3f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,12 +49,12 @@ jobs: # all of these default to true, but feel free to set to # "false" if necessary for your workflow - android: true + android: false dotnet: false haskell: true - large-packages: true - docker-images: true - swap-storage: true + large-packages: false + docker-images: false + swap-storage: false - name: Setup dotnet uses: actions/setup-dotnet@v4 with: diff --git a/Directory.Build.props b/Directory.Build.props index c1837c2fc..1ca9981b5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,6 +25,29 @@ false true + + + + <_Parameter1>$(InternalsVisibleToFriends) + + + + + + + + + + <_Parameter1>%(InternalsVisibleTo.Identity) + + + + + + <_Parameter1>$(AssemblyName)%(InternalsVisibleToSuffix.Identity) + + + true diff --git a/README.md b/README.md index 8c93e66c5..733820fdf 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ - Keeps compatibility with the custom uploader configuration format (.sxcu) - As a user, you do **NOT** need to have .NET installed. Whether you're on Linux, Windows, or macOS. -What does this all mean? It means you'll be able to have a more **performant**, **reliable**, and **stylish** application. +What does this all mean? You'll have an app that **flies**, is **reliable**, and looks **sleek**. You will *not* receive any support from the ShareX project for this software. \ If you have any issues with this project, please **open an issue** in this repository. diff --git a/SnapX.Avalonia/App.axaml.cs b/SnapX.Avalonia/App.axaml.cs index e5c14717e..41a9f0c63 100644 --- a/SnapX.Avalonia/App.axaml.cs +++ b/SnapX.Avalonia/App.axaml.cs @@ -5,28 +5,21 @@ using Avalonia.Layout; using Avalonia.Markup.Xaml; using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Platform; using Avalonia.Styling; using CommunityToolkit.Mvvm.DependencyInjection; -using CommunityToolkit.Mvvm.Input; -using CommunityToolkit.Mvvm.Messaging; using FluentAvalonia.UI.Windowing; -using Microsoft.Extensions.DependencyInjection; -using Serilog; using SnapX.Avalonia.ViewModels; using SnapX.Avalonia.Views; +using SnapX.Avalonia.Views.About; using SnapX.Avalonia.Views.Settings; -using SnapX.Avalonia.Views.Settings.Views; using SnapX.Core; -using SnapX.Core.Capture; -using SnapX.Core.Job; +using SnapX.Core.Interfaces; using SnapX.Core.Utils; using SnapX.Core.Utils.Native; namespace SnapX.Avalonia; -public partial class App : Application +public class App : Application { public App() { @@ -35,28 +28,18 @@ public App() public static SnapXAvalonia SnapX { get; private set; } = null!; public static MainWindow? MyMainWindow { get; private set; } - public static string TrayTitle => $"SnapX v{SimpleVersion()}"; - - private static string SimpleVersion() - { - var version = Version.Parse(Helpers.GetApplicationVersion()); - var versionString = $"{version.Major}.{version.Minor}.{version.Revision}"; - if (version.Build > 0) - versionString += $".{version.Build}"; - return versionString; - } public override void Initialize() { SnapX = new SnapXAvalonia(); // SnapX.setQualifier(" UI"); AvaloniaXamlLoader.Load(this); - AppDomain.CurrentDomain.UnhandledException += (Sender, Args) => + AppDomain.CurrentDomain.UnhandledException += (_, Args) => { - ShowErrorDialog(Lang.UnhandledException, Args.ExceptionObject as Exception); + ShowErrorDialog(Lang.UnhandledException, (Args.ExceptionObject as Exception)!); }; #if DEBUG - Current.AttachDevTools(); + Current?.AttachDevTools(); #endif // Default logic doesn't auto-detect windows theme anymore in designer @@ -109,7 +92,7 @@ private void ShowErrorDialog(string? title, Exception ex) // Padding = new Thickness(10), }); } - var version = Assembly.GetExecutingAssembly().GetName().Version; + var version = Assembly.GetExecutingAssembly().GetName().Version!; var semver = version.Major + "." + version.Minor + "." + version.Revision; stackPanel.Children.Add(new SelectableTextBlock { @@ -134,7 +117,7 @@ private void ShowErrorDialog(string? title, Exception ex) FontWeight = FontWeight.Bold, CornerRadius = new CornerRadius(5) }; - reportButton.Click += (sender, e) => OnReportErrorClicked(); + reportButton.Click += (_, _) => OnReportErrorClicked(); var githubButton = new Button { @@ -150,7 +133,7 @@ private void ShowErrorDialog(string? title, Exception ex) FontWeight = FontWeight.Bold, CornerRadius = new CornerRadius(5) }; - githubButton.Click += (sender, e) => OnGitHubButtonClicked(ex); + githubButton.Click += (_, _) => OnGitHubButtonClicked(ex); var copyButton = new Button @@ -169,7 +152,7 @@ private void ShowErrorDialog(string? title, Exception ex) }; // Copy error to clipboard when clicked - copyButton.Click += (sender, e) => CopyErrorToClipboard(ex.ToString()); + copyButton.Click += (_, _) => CopyErrorToClipboard(ex.ToString()); buttonPanel.Children.Add(reportButton); @@ -212,14 +195,14 @@ private void OnReportErrorClicked() { // For now, do nothing when the button is clicked // This is where Sentry comes in - Console.WriteLine("Report Error button clicked. No action yet. If you have telemetry enabled, (it is by default) it will have already been sent to Sentry."); + DebugHelper.WriteLine("Report Error button clicked. No action yet. If you have telemetry enabled, (it is by default) it will have already been sent to Sentry."); } - private void Shutdown() + public static void Shutdown() { try { - SnapX?.shutdown(); + SnapX.shutdown(); } catch (Exception e) { @@ -233,13 +216,7 @@ public override void OnFrameworkInitializationCompleted() { var locator = new ViewLocator(); DataTemplates.Add(locator); - var services = new ServiceCollection(); - ConfigureServices(services); - var provider = services.BuildServiceProvider(); - - Ioc.Default.ConfigureServices(provider); - Ioc.Default.AddStaticLogging(); var vm = Ioc.Default.GetRequiredService(); switch (ApplicationLifetime) @@ -253,7 +230,7 @@ public override void OnFrameworkInitializationCompleted() DebugHelper.WriteLine("Received Shutdown from Avalonia"); if (sigintReceived) return; sigintReceived = true; - SnapX.shutdown(); + Shutdown(); // desktop.Shutdown(); }; @@ -264,22 +241,9 @@ public override void OnFrameworkInitializationCompleted() if (sigintReceived) return; ea.Cancel = true; sigintReceived = true; - SnapX.shutdown(); + Shutdown(); desktop.Shutdown(); }; - // AppDomain.CurrentDomain.ProcessExit += (o, _) => - // { - // if (!sigintReceived) - // { - // sigintReceived = true; - // DebugHelper.WriteLine("Received SIGTERM"); - // SnapX.shutdown(); - // } - // else - // { - // DebugHelper.WriteLine("Received SIGTERM, ignoring it because already processed SIGINT"); - // } - // }; var errorStarting = false; // DebugHelper.Logger.Debug($"Avalonia Args: {desktop.Args}"); try @@ -299,97 +263,6 @@ public override void OnFrameworkInitializationCompleted() if (errorStarting) return; DebugHelper.WriteLine("Internal Startup time: {0} ms", SnapX.getStartupTime()); - var logoBitmap = new Bitmap(AssetLoader.Open(new Uri("avares://snapx-ui/SnapX_Logo.png"))); - var trayIcon = new TrayIcon - { - Icon = new WindowIcon(logoBitmap), - ToolTipText = Core.SnapX.AppName, - Command = OpenSnapXCommand - }; - - var menu = new NativeMenu(); - menu.Opening += NativeMenu_OnOpening; - menu.NeedsUpdate += NativeMenu_OnNeedsUpdate; - - var about = new NativeMenuItem(TrayTitle) - { - Icon = logoBitmap, - ToolTip = Lang.AboutSnapX - }; - about.Click += NativeMenuItem_SnapX_OnClick; - menu.Items.Add(about); - menu.Items.Add(new NativeMenuItemSeparator()); - - var capture = new NativeMenuItem("Capture") { Menu = new NativeMenu() }; - var full = new NativeMenuItem(Lang.UI_Capture_Fullscreen); - full.Click += NativeMenuItem_Capture_Fullscreen_OnClick; - capture.Menu.Items.Add(full); - - var windowPicker = new NativeMenuItem(Lang.UI_Dropdown_Window) - { - Menu = new NativeMenu - { - new NativeMenuItem("SnapX UI") { Icon = logoBitmap }, - new NativeMenuItem("Marvel Rivals") { Icon = logoBitmap }, - new NativeMenuItem("Man of Steel (2013)") { Icon = logoBitmap } - } - }; - capture.Menu.Items.Add(windowPicker); - - var monitorPicker = new NativeMenuItem(Lang.UI_Dropdown_Monitor) { Menu = [] }; - monitorPicker.Menu.NeedsUpdate += NativeMenu_OnNeedsUpdate; - capture.Menu.Items.Add(monitorPicker); - - capture.Menu.Items.Add(new NativeMenuItem("Region")); - capture.Menu.Items.Add(new NativeMenuItem("Region (Light)")); - capture.Menu.Items.Add(new NativeMenuItem("Region (Transparent)")); - menu.Items.Add(capture); - - menu.Items.Add(new NativeMenuItem("Upload") - { - Menu = new NativeMenu - { - new NativeMenuItem("Upload File..."), - new NativeMenuItem("Upload Folder..."), - new NativeMenuItem("Upload from clipboard..."), - new NativeMenuItem("Upload text..."), - new NativeMenuItem("Drag and drop upload..."), - new NativeMenuItem("Shorten URL..."), - new NativeMenuItem("Tweet message...") - } - }); - var captureFullscreenMenuItem = new NativeMenuItem("Capture entire screen"); - captureFullscreenMenuItem.Click += NativeMenuItem_Capture_Fullscreen_OnClick; - var captureActiveWindowMenuItem = new NativeMenuItem("Capture active window"); - captureActiveWindowMenuItem.Click += NativeMenuItem_Workflows_CaptureActiveWindow_OnClick; - var captureActiveScreenMenuItem = new NativeMenuItem("Capture active screen"); - captureActiveScreenMenuItem.Click += NativeMenuItem_Workflows_CaptureActiveScreen_OnClick; - var workflows = new NativeMenuItem("Workflows") - { - Menu = - [ - captureFullscreenMenuItem, - captureActiveScreenMenuItem, - captureActiveWindowMenuItem, - ] - }; - - menu.Items.Add(workflows); - - menu.Items.Add(new NativeMenuItemSeparator()); - - var open = new NativeMenuItem("Open"); - open.Command = OpenSnapXCommand; - menu.Items.Add(open); - - var quit = new NativeMenuItem("Quit"); - quit.Click += NativeMenuItem_Quit_OnClick; - menu.Items.Add(quit); - - trayIcon.Menu = menu; - - TrayIcon.SetIcons(Current, [trayIcon]); - if (SnapX.isSilent()) return; if (SnapX.GetCLIManager().IsCommandExist("video")) { @@ -402,9 +275,11 @@ public override void OnFrameworkInitializationCompleted() MyMainWindow = Window; desktop.MainWindow = Window; + var tray = new OSTray(this, Ioc.Default.GetRequiredService()); + tray.display(); break; } - case ISingleViewApplicationLifetime singleView when SnapX.isSilent(): + case ISingleViewApplicationLifetime when SnapX.isSilent(): return; case ISingleViewApplicationLifetime singleView: { @@ -452,6 +327,10 @@ public static void CreateAboutWindowStatic() aboutWindow.Show(); } } + public void NativeMenuAboutSnapXClick(object? _, EventArgs E) + { + CreateAboutWindowStatic(); + } public static void CreateSettingsWindowStatic() { var settingsWindow = Design.IsDesignMode @@ -470,87 +349,4 @@ public static void CreateSettingsWindowStatic() settingsWindow.Show(); } } - - - private void NativeMenuAboutSnapXClick(object? Sender, EventArgs E) - { - CreateAboutWindowStatic(); - } - - public static void ConfigureServices(IServiceCollection services) - { - services.AddLogging(loggingBuilder => - loggingBuilder.AddSerilog(dispose: true)); - - - services.AddTransient(); - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - services.AddTransient(); - services.AddSingleton(); - - services.AddTransient(); - services.AddSingleton(); - - services.AddSingleton(WeakReferenceMessenger.Default); - } - - private void NativeMenuItem_Quit_OnClick(object? Sender, EventArgs E) - { - Shutdown(); - } - - private void NativeMenuItem_SnapX_OnClick(object? Sender, EventArgs E) - { - NativeMenuAboutSnapXClick(Sender, E); - } - - private void NativeMenuItem_Capture_Fullscreen_OnClick(object? Sender, EventArgs E) - { - TaskHelpers.GetScreenshot().CaptureFullscreen(); - } - - private void NativeMenuItem_Workflows_CaptureActiveScreen_OnClick(object? Sender, EventArgs E) - { - new CaptureActiveMonitor().Capture(TaskSettings.GetDefaultTaskSettings()); - } - - private void NativeMenuItem_Workflows_CaptureActiveWindow_OnClick(object? Sender, EventArgs E) - { - new CaptureActiveWindow().Capture(TaskSettings.GetDefaultTaskSettings()); - } - - private void NativeMenuItem_Open_OnClick(object? Sender, EventArgs E) - { - if (!MyMainWindow?.IsLoaded ?? false) - { - var vm = Ioc.Default.GetRequiredService(); - MyMainWindow = new MainWindow(vm); - MyMainWindow.Show(); - } - - if (!MyMainWindow?.IsVisible ?? true) MyMainWindow?.Show(); - MyMainWindow?.Focus(); - MyMainWindow?.Activate(); - } - - [RelayCommand] - private void OpenSnapX() - { - NativeMenuItem_Open_OnClick(this, EventArgs.Empty); - } - private void NativeMenu_OnNeedsUpdate(object? Sender, EventArgs E) - { - DebugHelper.WriteLine("NativeMenu_OnNeedsUpdate"); - } - - private void NativeMenu_OnOpening(object? Sender, EventArgs E) - { - DebugHelper.WriteLine("NativeMenu_OnOpening"); - } } diff --git a/SnapX.Avalonia/Extensions/AvaloniaListExtensions.cs b/SnapX.Avalonia/Extensions/AvaloniaListExtensions.cs new file mode 100644 index 000000000..8ae9ff1b7 --- /dev/null +++ b/SnapX.Avalonia/Extensions/AvaloniaListExtensions.cs @@ -0,0 +1,20 @@ +using Avalonia.Collections; + +namespace SnapX.Avalonia.Extensions; + +public static class AvaloniaListExtensions +{ + public static int FindIndex(this AvaloniaList list, Predicate match) + { + if (match == null) + throw new ArgumentNullException(nameof(match)); + + for (int i = 0; i < list.Count; i++) + { + if (match(list[i])) + return i; + } + + return -1; + } +} diff --git a/SnapX.Avalonia/OSTray.cs b/SnapX.Avalonia/OSTray.cs new file mode 100644 index 000000000..0a3e2f36a --- /dev/null +++ b/SnapX.Avalonia/OSTray.cs @@ -0,0 +1,177 @@ +using Avalonia.Controls; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Input; +using SnapX.Avalonia.ViewModels; +using SnapX.Avalonia.Views; +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture; +using SnapX.Core.Utils; + +namespace SnapX.Avalonia; + +public partial class OSTray(App Current, ILoggerService Logger) +{ + private static string TrayTitle => $"{Core.SnapX.AppName} v{SimpleVersion()}"; + + private static string SimpleVersion() + { + var version = Version.Parse(Helpers.GetApplicationVersion()); + var versionString = $"{version.Major}.{version.Minor}.{version.Revision}"; + if (version.Build > 0) + versionString += $".{version.Build}"; + return versionString; + } + public void display() + { + var logoBitmap = new Bitmap(AssetLoader.Open(new Uri("avares://snapx-ui/SnapX_Logo.png"))); + var trayIcon = new TrayIcon + { + Icon = new WindowIcon(logoBitmap), + ToolTipText = Core.SnapX.AppName, + Command = OpenSnapXCommand + }; + + var menu = new NativeMenu(); + menu.Opening += NativeMenu_OnOpening; + menu.NeedsUpdate += NativeMenu_OnNeedsUpdate; + + var about = new NativeMenuItem(TrayTitle) + { + Icon = logoBitmap, + ToolTip = Lang.AboutSnapX + }; + about.Click += NativeMenuItem_SnapX_OnClick; + menu.Items.Add(about); + menu.Items.Add(new NativeMenuItemSeparator()); + + var capture = new NativeMenuItem("Capture") { Menu = new NativeMenu() }; + var full = new NativeMenuItem(Lang.UI_Capture_Fullscreen); + full.Click += NativeMenuItem_Capture_Fullscreen_OnClick; + capture.Menu.Items.Add(full); + + var windowPicker = new NativeMenuItem(Lang.UI_Dropdown_Window) + { + Menu = + [ + new NativeMenuItem("SnapX UI") { Icon = logoBitmap }, + new NativeMenuItem("Marvel Rivals") { Icon = logoBitmap }, + new NativeMenuItem("Man of Steel (2013)") { Icon = logoBitmap } + ] + }; + capture.Menu.Items.Add(windowPicker); + + var monitorPicker = new NativeMenuItem(Lang.UI_Dropdown_Monitor) { Menu = [] }; + monitorPicker.Menu.NeedsUpdate += NativeMenu_OnNeedsUpdate; + capture.Menu.Items.Add(monitorPicker); + + capture.Menu.Items.Add(new NativeMenuItem("Region")); + capture.Menu.Items.Add(new NativeMenuItem("Region (Light)")); + capture.Menu.Items.Add(new NativeMenuItem("Region (Transparent)")); + menu.Items.Add(capture); + + menu.Items.Add(new NativeMenuItem("Upload") + { + Menu = + [ + new NativeMenuItem("Upload File..."), + new NativeMenuItem("Upload Folder..."), + new NativeMenuItem("Upload from clipboard..."), + new NativeMenuItem("Upload text..."), + new NativeMenuItem("Drag and drop upload..."), + new NativeMenuItem("Shorten URL..."), + new NativeMenuItem("Tweet message...") + ] + }); + var captureFullscreenMenuItem = new NativeMenuItem("Capture entire screen"); + captureFullscreenMenuItem.Click += NativeMenuItem_Capture_Fullscreen_OnClick; + var captureActiveWindowMenuItem = new NativeMenuItem("Capture active window"); + captureActiveWindowMenuItem.Click += NativeMenuItem_Workflows_CaptureActiveWindow_OnClick; + var captureActiveScreenMenuItem = new NativeMenuItem("Capture active screen"); + captureActiveScreenMenuItem.Click += NativeMenuItem_Workflows_CaptureActiveScreen_OnClick; + var workflows = new NativeMenuItem("Workflows") + { + Menu = + [ + captureFullscreenMenuItem, + captureActiveScreenMenuItem, + captureActiveWindowMenuItem, + ] + }; + + menu.Items.Add(workflows); + + menu.Items.Add(new NativeMenuItemSeparator()); + + var open = new NativeMenuItem("Open") + { + Command = OpenSnapXCommand + }; + menu.Items.Add(open); + + var quit = new NativeMenuItem("Quit"); + quit.Click += NativeMenuItem_Quit_OnClick; + menu.Items.Add(quit); + + trayIcon.Menu = menu; + + TrayIcon.SetIcons(Current, [trayIcon]); + } + private void NativeMenuItem_Quit_OnClick(object? Sender, EventArgs E) + { + App.Shutdown(); + } + private void NativeMenuItem_SnapX_OnClick(object? Sender, EventArgs E) + { + Current.NativeMenuAboutSnapXClick(Sender, E); + } + + private void NativeMenuItem_Capture_Fullscreen_OnClick(object? Sender, EventArgs E) + { + TaskHelpers.GetScreenshot().CaptureFullscreen(); + } + + private void NativeMenuItem_Workflows_CaptureActiveScreen_OnClick(object? Sender, EventArgs E) + { + var capture = Ioc.Default.GetRequiredService(); + capture.CaptureAsync(TaskSettings.GetDefaultTaskSettings()); + } + + private void NativeMenuItem_Workflows_CaptureActiveWindow_OnClick(object? Sender, EventArgs E) + { + var capture = Ioc.Default.GetRequiredService(); + capture.CaptureAsync(TaskSettings.GetDefaultTaskSettings()); + } + + private void NativeMenuItem_Open_OnClick(object? _, EventArgs _2) + { + var MyMainWindow = App.MyMainWindow; + if (!MyMainWindow?.IsLoaded ?? false) + { + var vm = Ioc.Default.GetRequiredService(); + MyMainWindow = new MainWindow(vm); + MyMainWindow.Show(); + } + + if (!MyMainWindow?.IsVisible ?? true) MyMainWindow?.Show(); + MyMainWindow?.Focus(); + MyMainWindow?.Activate(); + } + + [RelayCommand] + private void OpenSnapX() + { + NativeMenuItem_Open_OnClick(this, EventArgs.Empty); + } + private void NativeMenu_OnNeedsUpdate(object? Sender, EventArgs E) + { + Logger.Information("NativeMenu_OnNeedsUpdate"); + } + + private void NativeMenu_OnOpening(object? Sender, EventArgs E) + { + Logger.Information("NativeMenu_OnOpening"); + } +} diff --git a/SnapX.Avalonia/Program.cs b/SnapX.Avalonia/Program.cs index 47789765e..4ca698d11 100644 --- a/SnapX.Avalonia/Program.cs +++ b/SnapX.Avalonia/Program.cs @@ -5,10 +5,14 @@ using Avalonia.Media; using SnapX.Avalonia; +var snapx = new SnapXAvalonia(); + +snapx.loadApplicationSettingsPartial(); + BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); -static AppBuilder BuildAvaloniaApp() +AppBuilder BuildAvaloniaApp() { var builder = AppBuilder.Configure() .WithInterFont(); @@ -19,11 +23,11 @@ static AppBuilder BuildAvaloniaApp() builder = builder.With(new FontManagerOptions { DefaultFamilyName = "fonts:Inter#Inter", - FontFallbacks = new List - { + FontFallbacks = + [ new() { - FontFamily = "Inter" + FontFamily = "fonts:Inter#Inter" }, new() { @@ -41,12 +45,13 @@ static AppBuilder BuildAvaloniaApp() { FontFamily = "Adwaita Sans" } - } + ] }); } builder = builder.LogToTrace(); + var useGPU = snapx.GetConfiguration().HardwareAccelerated; var x11Options = new X11PlatformOptions { // Fixes poor performance on my NVIDIA RTX 3060 Laptop GPU using Region Selector on Fedora KDE Wayland @@ -54,6 +59,21 @@ static AppBuilder BuildAvaloniaApp() UseRetainedFramebuffer = true, OverlayPopups = true }; + if (!useGPU) x11Options.RenderingMode = [X11RenderingMode.Software]; + + var macOSOptions = new AvaloniaNativePlatformOptions + { + RenderingMode = [AvaloniaNativeRenderingMode.Metal, AvaloniaNativeRenderingMode.OpenGl, AvaloniaNativeRenderingMode.Software], + OverlayPopups = true + }; + if (!useGPU) macOSOptions.RenderingMode = [AvaloniaNativeRenderingMode.Software]; + + var win32Options = new Win32PlatformOptions + { + // RenderingMode = [Win32RenderingMode.Vulkan, Win32RenderingMode.AngleEgl, Win32RenderingMode.Wgl, Win32RenderingMode.Software], + OverlayPopups = true + }; + if (!useGPU) win32Options.RenderingMode = [Win32RenderingMode.Software]; if (OperatingSystem.IsFreeBSD()) { @@ -68,8 +88,8 @@ static AppBuilder BuildAvaloniaApp() .UsePlatformDetect() .UseManagedSystemDialogs() .With(x11Options) - .With(new AvaloniaNativePlatformOptions { OverlayPopups = true }) - .With(new Win32PlatformOptions { OverlayPopups = true }); + .With(macOSOptions) + .With(win32Options); } return builder; diff --git a/SnapX.Avalonia/SnapX.Avalonia.csproj b/SnapX.Avalonia/SnapX.Avalonia.csproj index d830e24a0..643c0a94f 100644 --- a/SnapX.Avalonia/SnapX.Avalonia.csproj +++ b/SnapX.Avalonia/SnapX.Avalonia.csproj @@ -11,6 +11,7 @@ snapx-ui SnapX UI Assets\SnapX_Icon.ico + SnapX.Avalonia.Tests false true @@ -48,7 +49,6 @@ - diff --git a/SnapX.Avalonia/SnapXAvalonia.cs b/SnapX.Avalonia/SnapXAvalonia.cs index edd10612f..0acb7beb3 100644 --- a/SnapX.Avalonia/SnapXAvalonia.cs +++ b/SnapX.Avalonia/SnapXAvalonia.cs @@ -1,3 +1,53 @@ +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using SnapX.Avalonia.ViewModels; +using SnapX.Avalonia.Views; +using SnapX.Avalonia.Views.About; +using SnapX.Avalonia.Views.Settings; +using SnapX.Avalonia.Views.Settings.Views; +using SnapX.CommonUI.ViewModels; + namespace SnapX.Avalonia; -public class SnapXAvalonia : Core.SnapX; +public class SnapXAvalonia() : SnapX.Core.SnapX(BuildServices()) +{ + private static IServiceProvider BuildServices() + { + var services = new ServiceCollection(); + Core.SnapX.ConfigureServices(services); + ConfigureServices(services); + var provider = services.BuildServiceProvider(); + + try + { + Ioc.Default.ConfigureServices(provider); + } + catch (Exception ex) + { + Log.Error(ex, "Failed to configure services"); + } + Ioc.Default.AddStaticLogging(); + + return services.BuildServiceProvider(); + } + public static void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddTransient(); + services.AddSingleton(); + + services.AddTransient(); + services.AddSingleton(); + + services.AddSingleton(WeakReferenceMessenger.Default); + } +} diff --git a/SnapX.Avalonia/ViewLocator.cs b/SnapX.Avalonia/ViewLocator.cs index 0bb7eb282..77cd51482 100644 --- a/SnapX.Avalonia/ViewLocator.cs +++ b/SnapX.Avalonia/ViewLocator.cs @@ -7,6 +7,7 @@ using SnapX.Avalonia.Views; using SnapX.Avalonia.Views.Settings; using SnapX.Avalonia.Views.Settings.Views; +using SnapX.CommonUI.ViewModels; namespace SnapX.Avalonia; diff --git a/SnapX.Avalonia/ViewModels/HomePageViewModel.cs b/SnapX.Avalonia/ViewModels/HomePageViewModel.cs index bb7cada92..6081980c8 100644 --- a/SnapX.Avalonia/ViewModels/HomePageViewModel.cs +++ b/SnapX.Avalonia/ViewModels/HomePageViewModel.cs @@ -4,8 +4,10 @@ using Avalonia.Input; using Avalonia.Threading; using CommunityToolkit.Mvvm.Input; -using SnapX.Avalonia.Models; +using SnapX.Avalonia.Extensions; using SnapX.Avalonia.Views; +using SnapX.CommonUI.Models; +using SnapX.CommonUI.ViewModels; using SnapX.Core; using SnapX.Core.Job; using SnapX.Core.Upload; @@ -16,78 +18,75 @@ namespace SnapX.Avalonia.ViewModels; public partial class HomePageViewModel : ViewModelBase { public AvaloniaList SelectedTasks { get; set; } = []; - public AvaloniaList recentTasks { get; set; } = - []; - private System.Timers.Timer _refreshTimer; - private bool _isRefreshing; // Guard flag to prevent concurrent refreshes + public AvaloniaList recentTasks { get; set; } = []; + private readonly System.Timers.Timer _refreshTimer = new(5000); // Refresh every 5 seconds + private bool _isRefreshing; private int _failedRefreshTasks; - private DateTime _lastCacheTime = DateTime.MinValue; - private List _cachedTasks; - private readonly TimeSpan _cacheDuration = TimeSpan.FromSeconds(4); - public void InvalidateCache() { - _lastCacheTime = DateTime.MinValue; - _cachedTasks = []; - } - public HomePageViewModel() - { - // ShowContextMenuCommand = new RelayCommand(ShowContextMenu); - _refreshTimer = new System.Timers.Timer(5000); // Refresh every 5 seconds } + // ShowContextMenuCommand = new RelayCommand(ShowContextMenu); - public async Task Initialize() + public Task Initialize() { TaskManager.InitHistoryManager(); _refreshTimer.Elapsed += OnRefreshTimerElapsed; _refreshTimer.AutoReset = true; _refreshTimer.Start(); - RefreshTasks(); + _ = RefreshTasks(); + return Task.CompletedTask; } public void StopTimer() => _refreshTimer.Stop(); public void StartTimer() => _refreshTimer.Start(); private async void OnRefreshTimerElapsed(object sender, ElapsedEventArgs e) { - if (_isRefreshing) - { - DebugHelper.WriteLine("Previous timer run already in progress. Skipping this timer tick."); - // Apply more conservative _refreshTimer interval when we know that there's a bunch of tasks. - if (recentTasks.Count > 3000) _refreshTimer.Interval = 10_000; - if (_failedRefreshTasks > 15) _refreshTimer.Interval = 30_000; - if (_failedRefreshTasks > 10) _refreshTimer.Interval = 20_000; - if (_failedRefreshTasks > 5) _refreshTimer.Interval = 10_000; - if (_failedRefreshTasks > 19) _refreshTimer.Interval = 60_000; - // Fuck it, give up. - if (_failedRefreshTasks > 20) _refreshTimer.Stop(); - _failedRefreshTasks++; - return; - } - - _isRefreshing = true; try { - // ConfigureAwait(false) is good practice here as it's background work. - await RefreshTasks().ConfigureAwait(false); + if (_isRefreshing) + { + DebugHelper.WriteLine("Previous timer run already in progress. Skipping this timer tick."); + // Apply more conservative _refreshTimer interval when we know that there's a bunch of tasks. + if (recentTasks.Count > 3000) _refreshTimer.Interval = 10_000; + if (_failedRefreshTasks > 15) _refreshTimer.Interval = 30_000; + if (_failedRefreshTasks > 10) _refreshTimer.Interval = 20_000; + if (_failedRefreshTasks > 5) _refreshTimer.Interval = 10_000; + if (_failedRefreshTasks > 19) _refreshTimer.Interval = 60_000; + // Fuck it, give up. + if (_failedRefreshTasks > 20) _refreshTimer.Stop(); + _failedRefreshTasks++; + return; + } + + _isRefreshing = true; + try + { + await RefreshTasks().ConfigureAwait(false); + } + catch (Exception ex) + { + DebugHelper.WriteException(ex); + } + finally + { + _isRefreshing = false; + } } catch (Exception ex) { - DebugHelper.WriteException(ex); - } - finally - { - _isRefreshing = false; // Reset the flag when the refresh is complete (or fails) + DebugHelper.WriteException(ex, "Error while refreshing tasks"); } } [RelayCommand] public void ContextMenuSelection(object Sender) { - SelectedTasks.Add(Sender as ListTaskTemplate); + if (Sender is not ListTaskTemplate Template) return; + SelectedTasks.Add(Template); } [RelayCommand] public void DeleteHistoryItemLocally(object Sender) { - var ltt = Sender as ListTaskTemplate; + if (Sender is not ListTaskTemplate ltt) return; var task = ltt.task; if (string.IsNullOrWhiteSpace(task.FilePath)) { @@ -113,7 +112,7 @@ public void RemoveHistoryItem(object Sender) if (Sender is not ListTaskTemplate ltt) return; var task = ltt.task; DebugHelper.WriteLine($"Removing {task.FilePath ?? task.FileName} (Id: {task.Id}) from history"); - var success = TaskManager.History.RemoveHistoryItem(task); + var success = TaskManager.History.RemoveHistoryItems([task]); var status = success ? "Success" : "Failure"; DebugHelper.WriteLine($"{status} removing history item {task.FilePath ?? task.FileName}"); } @@ -148,7 +147,7 @@ private void OnPointerPress(object sender, PointerPressedEventArgs e) if (e.GetCurrentPoint(button).Properties.IsRightButtonPressed) { - // Right-click: Show context menu on the toggle button itself + // Right-click: Show a context menu on the toggle button itself vm.ContextMenuSelectionCommand.Execute(button); } else if (e.GetCurrentPoint(button).Properties.IsLeftButtonPressed) @@ -205,66 +204,61 @@ public async Task RefreshTasks() { var typeofVM = typeof(HomePageViewModel); - List newDesiredTasks; + var historyItems = await TaskManager.History.GetHistoryItemsAsync().ConfigureAwait(false); - // Check cache first - if (DateTime.Now - _lastCacheTime < _cacheDuration && _cachedTasks != null) - { - newDesiredTasks = _cachedTasks; - } - else - { - var historyItems = await TaskManager.History.GetHistoryItemsAsync(30_000).ConfigureAwait(false); + var tasks = historyItems + .Select(task => new ListTaskTemplate(typeofVM, task)) + .OrderByDescending(item => item.task.Id) + .ToList(); - var tasks = historyItems.Select(task => new ListTaskTemplate(typeofVM, task)); + List toAdd = []; + List toUpdate = []; + List toRemove; - newDesiredTasks = tasks - .OrderByDescending(item => item.task.Id) + { + var currentTasksById = recentTasks.ToDictionary(t => t.task.Id); + var newTaskIds = tasks.Select(t => t.task.Id).ToHashSet(); + + toRemove = recentTasks + .Where(t => !newTaskIds.Contains(t.task.Id)) + .Select(t => t.task.Id) .ToList(); - _cachedTasks = newDesiredTasks; - _lastCacheTime = DateTime.Now; + foreach (var newItem in tasks) + { + if (currentTasksById.TryGetValue(newItem.task.Id, out var existing)) + { + if (!existing.Equals(newItem)) + toUpdate.Add(newItem); + } + else + { + toAdd.Add(newItem); + } + } } - + // Warning: Computations on the UIThread are precious. await Dispatcher.UIThread.InvokeAsync(() => { - if (newDesiredTasks.Count > 50_000) - { - recentTasks.ResetBehavior = ResetBehavior.Remove; - recentTasks.Clear(); - recentTasks.AddRange(newDesiredTasks); - return; - } - var currentTasksById = recentTasks.ToDictionary(template => template.task.Id); - - var newDesiredTaskIds = newDesiredTasks.Select(template => template.task.Id).ToHashSet(); for (var i = recentTasks.Count - 1; i >= 0; i--) { - if (!newDesiredTaskIds.Contains(recentTasks[i].task.Id)) - { + if (toRemove.Contains(recentTasks[i].task.Id)) recentTasks.RemoveAt(i); - } } - foreach (var newItem in newDesiredTasks) + foreach (var item in toUpdate) { - if (currentTasksById.TryGetValue(newItem.task.Id, out var existingItem)) - { - if (existingItem.Equals(newItem)) - { - continue; - } - var index = recentTasks.IndexOf(existingItem); - if (index == -1) continue; - recentTasks.RemoveAt(index); - recentTasks.Insert(index, newItem); - } - else - { - recentTasks.Insert(0, newItem); - } + var index = recentTasks.FindIndex(t => t.task.Id == item.task.Id); + if (index == -1) continue; + recentTasks.RemoveAt(index); + recentTasks.Insert(index, item); + } + + foreach (var item in toAdd) + { + recentTasks.Insert(0, item); } - }); + }).GetTask().ConfigureAwait(false); } } diff --git a/SnapX.Avalonia/ViewModels/MainViewModel.cs b/SnapX.Avalonia/ViewModels/MainViewModel.cs index 65f571d07..5a06bbd52 100644 --- a/SnapX.Avalonia/ViewModels/MainViewModel.cs +++ b/SnapX.Avalonia/ViewModels/MainViewModel.cs @@ -4,7 +4,8 @@ using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; -using SnapX.Avalonia.Models; +using SnapX.CommonUI.Models; +using SnapX.CommonUI.ViewModels; namespace SnapX.Avalonia.ViewModels; @@ -37,11 +38,9 @@ public MainViewModel() : this(new WeakReferenceMessenger()) { } partial void OnSelectedListItemChanged(ListItemTemplate? value) { if (value is null) return; -#pragma warning disable IL2072 // The code works, leave me alone var vm = Design.IsDesignMode ? Activator.CreateInstance(value.ModelType) : Ioc.Default.GetService(value.ModelType); -#pragma warning restore IL2072 if (vm is not ViewModelBase vmb) return; diff --git a/SnapX.Avalonia/Views/About/AboutWindow.axaml b/SnapX.Avalonia/Views/About/AboutWindow.axaml index 142b5deae..66c648d5d 100644 --- a/SnapX.Avalonia/Views/About/AboutWindow.axaml +++ b/SnapX.Avalonia/Views/About/AboutWindow.axaml @@ -8,18 +8,18 @@ d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d" - x:Class="SnapX.Avalonia.AboutWindow" - x:DataType="viewModels:AboutWindowViewModel" + x:Class="SnapX.Avalonia.Views.About.AboutWindow" + x:DataType="viewModels1:AboutWindowViewModel" xmlns="https://github.com/avaloniaui" xmlns:avalonia="clr-namespace:FluentIcons.Avalonia;assembly=FluentIcons.Avalonia" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" - xmlns:viewModels="clr-namespace:SnapX.Avalonia.ViewModels" + xmlns:viewModels1="clr-namespace:SnapX.CommonUI.ViewModels;assembly=SnapX.CommonUI" xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + diff --git a/SnapX.Avalonia/Views/About/AboutWindow.axaml.cs b/SnapX.Avalonia/Views/About/AboutWindow.axaml.cs index 6b88537e2..565a1ab4f 100644 --- a/SnapX.Avalonia/Views/About/AboutWindow.axaml.cs +++ b/SnapX.Avalonia/Views/About/AboutWindow.axaml.cs @@ -8,11 +8,11 @@ using FluentAvalonia.Styling; using FluentAvalonia.UI.Media; using FluentAvalonia.UI.Windowing; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; using SnapX.Core; using SnapX.Core.Utils; -namespace SnapX.Avalonia; +namespace SnapX.Avalonia.Views.About; public partial class AboutWindow : AppWindow { diff --git a/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml b/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml index b4cd64994..7902f1f07 100644 --- a/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml +++ b/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml @@ -4,17 +4,16 @@ d:DesignWidth="800" mc:Ignorable="d" x:Class="SnapX.Avalonia.Views.Controls.ChangelogControl" - x:DataType="viewModels:ChangelogViewModel" + x:DataType="viewModels1:ChangelogViewModel" xmlns="https://github.com/avaloniaui" xmlns:commonUi="clr-namespace:SnapX.CommonUI;assembly=SnapX.CommonUI" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:fa="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:markdown="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:viewModels="clr-namespace:SnapX.Avalonia.ViewModels" + xmlns:viewModels1="clr-namespace:SnapX.CommonUI.ViewModels;assembly=SnapX.CommonUI" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + diff --git a/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml.cs b/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml.cs index 14c482f8d..0b77b4bea 100644 --- a/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml.cs +++ b/SnapX.Avalonia/Views/Controls/ChangelogControl.axaml.cs @@ -1,6 +1,6 @@ using Avalonia.Controls; using Avalonia.Interactivity; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; namespace SnapX.Avalonia.Views.Controls; diff --git a/SnapX.Avalonia/Views/HomePageView.axaml b/SnapX.Avalonia/Views/HomePageView.axaml index 6e1b0a87f..fa55ff047 100644 --- a/SnapX.Avalonia/Views/HomePageView.axaml +++ b/SnapX.Avalonia/Views/HomePageView.axaml @@ -15,7 +15,7 @@ xmlns:extensions="clr-namespace:SnapX.Avalonia.Extensions" xmlns:fluent1="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:models="clr-namespace:SnapX.Avalonia.Models" + xmlns:models="clr-namespace:SnapX.CommonUI.Models;assembly=SnapX.CommonUI" xmlns:viewModels1="clr-namespace:SnapX.Avalonia.ViewModels" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> diff --git a/SnapX.Avalonia/Views/HomePageView.axaml.cs b/SnapX.Avalonia/Views/HomePageView.axaml.cs index 75d2e1b14..2bd406392 100644 --- a/SnapX.Avalonia/Views/HomePageView.axaml.cs +++ b/SnapX.Avalonia/Views/HomePageView.axaml.cs @@ -2,8 +2,8 @@ using Avalonia.Controls; using Avalonia.Interactivity; using FluentAvalonia.UI.Controls; -using SnapX.Avalonia.Models; using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.Models; using SnapX.Core; using SnapX.Core.Utils; using SnapX.Core.Utils.Miscellaneous; diff --git a/SnapX.Avalonia/Views/LogViewer.axaml b/SnapX.Avalonia/Views/LogViewer.axaml index 70bcf458d..af946522e 100644 --- a/SnapX.Avalonia/Views/LogViewer.axaml +++ b/SnapX.Avalonia/Views/LogViewer.axaml @@ -1,7 +1,7 @@ RefreshLogs(); } - private void AppWindow_OnLoaded(object? sender, RoutedEventArgs e) + private void AppWindow_OnLoaded(object? sender, EventArgs e) { - _scrollViewer = this.FindControl("ScrollViewer"); - _logTextBlock = this.FindControl("LogTextBlock"); - _lastDisplayedLogCount = 0; - _refreshTimer.Start(); + RefreshLogs(); + DebugHelper.observableSink.LogMessageReceived += (_, _) => RefreshLogs(); } private void AppWindow_OnClosed(object? sender, EventArgs e) { _lastDisplayedLogCount = 0; - _refreshTimer.Stop(); } private void Close_Click(object? sender, RoutedEventArgs e) => Close(); private void RefreshLogs() { - if (DebugHelper.LogEvents.Count() <= _lastDisplayedLogCount) return; - for (var i = _lastDisplayedLogCount; i < DebugHelper.LogEvents.Count(); i++) + _scrollViewer = this.FindControl("ScrollViewer"); + _logTextBlock = this.FindControl("LogTextBlock"); + var bufferedEvents = DebugHelper.observableSink.GetBufferedEvents(); + for (var i = _lastDisplayedLogCount; i < bufferedEvents.Count; i++) { - var logEvent = DebugHelper.LogEvents.ElementAt(i); + var logEvent = DebugHelper.observableSink.GetBufferedEvents().ElementAt(i); var timestamp = logEvent.Timestamp.ToString("hh:mm:ss"); var level = logEvent.Level.ToString().ToUpper(); if (level == "INFORMATION") level = "INFO"; @@ -64,7 +56,7 @@ private void RefreshLogs() _logTextBlock.Inlines!.Add(new Run($"{timestamp} ") { - Foreground = Brushes.DimGray // Use DimGray for a softer grey that works well on dark backgrounds + Foreground = Brushes.DimGray }); _logTextBlock.Inlines.Add(new Run($"[{level}] ") @@ -81,7 +73,7 @@ private void RefreshLogs() Foreground = Brushes.DarkRed }); } - _lastDisplayedLogCount = DebugHelper.LogEvents.Count(); + _lastDisplayedLogCount = bufferedEvents.Count; } } private IBrush GetBrushForLevel(LogEventLevel level) @@ -92,66 +84,66 @@ private IBrush GetBrushForLevel(LogEventLevel level) { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(60, 60, 60), 0), - new GradientStop(Color.FromRgb(40, 40, 40), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(60, 60, 60), 0), + new GradientStop(Color.FromRgb(40, 40, 40), 1) + ] }, LogEventLevel.Debug => new LinearGradientBrush { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(50, 100, 150), 0), - new GradientStop(Color.FromRgb(30, 70, 120), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(50, 100, 150), 0), + new GradientStop(Color.FromRgb(30, 70, 120), 1) + ] }, LogEventLevel.Information => new LinearGradientBrush { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(70, 130, 70), 0), - new GradientStop(Color.FromRgb(40, 90, 40), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(70, 130, 70), 0), + new GradientStop(Color.FromRgb(40, 90, 40), 1) + ] }, LogEventLevel.Warning => new LinearGradientBrush { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(200, 160, 0), 0), - new GradientStop(Color.FromRgb(150, 110, 0), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(200, 160, 0), 0), + new GradientStop(Color.FromRgb(150, 110, 0), 1) + ] }, LogEventLevel.Error => new LinearGradientBrush { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(180, 50, 50), 0), - new GradientStop(Color.FromRgb(130, 30, 30), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(180, 50, 50), 0), + new GradientStop(Color.FromRgb(130, 30, 30), 1) + ] }, LogEventLevel.Fatal => new LinearGradientBrush { StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative), EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative), - GradientStops = new GradientStops - { - new GradientStop(Color.FromRgb(100, 0, 0), 0), - new GradientStop(Color.FromRgb(30, 0, 0), 1) - } + GradientStops = + [ + new GradientStop(Color.FromRgb(100, 0, 0), 0), + new GradientStop(Color.FromRgb(30, 0, 0), 1) + ] }, _ => new SolidColorBrush(Colors.DimGray) @@ -170,13 +162,13 @@ private void OpenLogFolderButton_OnClick(object? Sender, RoutedEventArgs E) private void UploadLogButton_OnClick(object? Sender, RoutedEventArgs E) { - UploadManager.UploadText(_logTextBlock.Inlines?.OfType() + UploadManager.UploadText(_logTextBlock?.Inlines?.OfType() .Aggregate("", (current, run) => current + run.Text)!); } private void CopyButton_OnClick(object? Sender, RoutedEventArgs E) { - Clipboard?.SetTextAsync(_logTextBlock.Inlines?.OfType().Aggregate("", (current, run) => current + run.Text)!); + Clipboard?.SetTextAsync(_logTextBlock?.Inlines?.OfType().Aggregate("", (current, run) => current + run.Text)!); } private void LogTextBlock_OnSizeChanged(object? Sender, SizeChangedEventArgs e) diff --git a/SnapX.Avalonia/Views/MainView.axaml.cs b/SnapX.Avalonia/Views/MainView.axaml.cs index df5806ca7..ebf22deeb 100644 --- a/SnapX.Avalonia/Views/MainView.axaml.cs +++ b/SnapX.Avalonia/Views/MainView.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.LogicalTree; using CommunityToolkit.Mvvm.Input; using FluentAvalonia.UI.Controls; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; using SnapX.Core; using SnapX.Core.Job; using SnapX.Core.Upload; diff --git a/SnapX.Avalonia/Views/MainWindow.axaml.cs b/SnapX.Avalonia/Views/MainWindow.axaml.cs index 2c3c11ee0..d9a9e67c0 100644 --- a/SnapX.Avalonia/Views/MainWindow.axaml.cs +++ b/SnapX.Avalonia/Views/MainWindow.axaml.cs @@ -1,9 +1,7 @@ using Avalonia; using Avalonia.Controls; -using Avalonia.Interactivity; using Avalonia.Media; using Avalonia.Media.Immutable; -using Avalonia.Platform.Storage; using Avalonia.Styling; using FluentAvalonia.Styling; using FluentAvalonia.UI.Media; @@ -13,7 +11,6 @@ using SnapX.Avalonia.Views.Controls; using SnapX.Core; using SnapX.Core.Job; -using SnapX.Core.Upload; using SnapX.Core.Utils; using Color = Avalonia.Media.Color; @@ -53,48 +50,9 @@ public MainWindow(MainViewModel vm) Position = new PixelPoint(config.MainFormPosition.X, config.MainFormPosition.Y); } InitializeComponent(); - ListenForEvents(); } public MainWindow() : this(new MainViewModel()) { } - public void ListenForEvents() - { - Core.SnapX.EventAggregator.Subscribe(HandleFileSelectionRequested); - } - private async void HandleFileSelectionRequested(NeedFileOpenerEvent @event) - { - var topLevel = TopLevel.GetTopLevel(this); - var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - Title = @event.Title, - AllowMultiple = @event.Multiselect, - SuggestedFileName = @event.FileName, - SuggestedStartLocation = await StorageProvider.TryGetFolderFromPathAsync(@event.Directory) - }); - - if (files.Count > 0) - { - string?[] filePaths = files.Select(f => f.Path.ToString()).ToArray(); - UploadManager.UploadFile(filePaths, @event.TaskSettings); - } - } - - // Event handler for the button click - private void OnDemoTestButtonClick(object sender, RoutedEventArgs e) - { - DebugHelper.WriteLine("Upload Demo Image triggered"); - - // try - // { - // var imageUrl = ImageURLTextBox.Text ?? ImageURLTextBox.Watermark; - // UploadManager.DownloadAndUploadFile(imageUrl!); - // } - // catch (Exception ex) - // { - // DebugHelper.Logger.Error(ex.ToString()); - // } - } - private void ApplicationActualThemeVariantChanged(object? sender, EventArgs e) { if (!OperatingSystem.IsWindows()) return; diff --git a/SnapX.Avalonia/Views/OCR.axaml b/SnapX.Avalonia/Views/OCR.axaml index 52faf3554..a5e676217 100644 --- a/SnapX.Avalonia/Views/OCR.axaml +++ b/SnapX.Avalonia/Views/OCR.axaml @@ -6,7 +6,7 @@ x:Class="SnapX.Avalonia.Views.OCR" x:DataType="viewModels:OCRViewModel" xmlns="https://github.com/avaloniaui" - xmlns:viewModels="clr-namespace:SnapX.Avalonia.ViewModels" + xmlns:viewModels="clr-namespace:SnapX.CommonUI.ViewModels;assembly=SnapX.CommonUI" xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> diff --git a/SnapX.Avalonia/Views/OCR.axaml.cs b/SnapX.Avalonia/Views/OCR.axaml.cs index 3cd0d93ef..2ae007f6a 100644 --- a/SnapX.Avalonia/Views/OCR.axaml.cs +++ b/SnapX.Avalonia/Views/OCR.axaml.cs @@ -1,7 +1,7 @@ using Avalonia.Controls; using Avalonia.Interactivity; using FluentAvalonia.UI.Windowing; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; using SnapX.Core; using SnapX.Core.History; using SnapX.Core.Utils; diff --git a/SnapX.Avalonia/Views/RegionSelectorWindow.axaml b/SnapX.Avalonia/Views/RegionSelectorWindow.axaml index ea4390048..f00e9b865 100644 --- a/SnapX.Avalonia/Views/RegionSelectorWindow.axaml +++ b/SnapX.Avalonia/Views/RegionSelectorWindow.axaml @@ -24,7 +24,7 @@ xmlns="https://github.com/avaloniaui" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:viewModels="clr-namespace:SnapX.Avalonia.ViewModels" + xmlns:viewModels="clr-namespace:SnapX.CommonUI.ViewModels;assembly=SnapX.CommonUI" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> diff --git a/SnapX.Avalonia/Views/RegionSelectorWindow.axaml.cs b/SnapX.Avalonia/Views/RegionSelectorWindow.axaml.cs index 7f08ec7ce..33d301613 100644 --- a/SnapX.Avalonia/Views/RegionSelectorWindow.axaml.cs +++ b/SnapX.Avalonia/Views/RegionSelectorWindow.axaml.cs @@ -8,7 +8,7 @@ using Avalonia.Threading; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; using SnapX.Core; using SnapX.Core.Job; using SnapX.Core.Upload; diff --git a/SnapX.Avalonia/Views/Settings/SettingsWindow.axaml.cs b/SnapX.Avalonia/Views/Settings/SettingsWindow.axaml.cs index cf275b9c8..984136645 100644 --- a/SnapX.Avalonia/Views/Settings/SettingsWindow.axaml.cs +++ b/SnapX.Avalonia/Views/Settings/SettingsWindow.axaml.cs @@ -1,5 +1,5 @@ using FluentAvalonia.UI.Windowing; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; namespace SnapX.Avalonia.Views.Settings; diff --git a/SnapX.Avalonia/Views/Settings/Views/SettingsHomePageView.axaml.cs b/SnapX.Avalonia/Views/Settings/Views/SettingsHomePageView.axaml.cs index dec3c44b0..5a231e25d 100644 --- a/SnapX.Avalonia/Views/Settings/Views/SettingsHomePageView.axaml.cs +++ b/SnapX.Avalonia/Views/Settings/Views/SettingsHomePageView.axaml.cs @@ -1,18 +1,16 @@ using Avalonia.Controls; using Avalonia.Media; -using SnapX.Avalonia.ViewModels; +using SnapX.CommonUI.ViewModels; using SnapX.Core; namespace SnapX.Avalonia.Views.Settings.Views; public partial class SettingsHomePageView : UserControl { - private SettingsHomePageViewVM ViewModel; public SettingsHomePageView(SettingsHomePageViewVM vm) { DataContext = vm; - ViewModel = vm; InitializeComponent(); var itemsAsList = FontManager.Current.SystemFonts .OrderBy(font => font.Name) diff --git a/SnapX.Avalonia/Views/Settings/Views/SettingsMainView.axaml b/SnapX.Avalonia/Views/Settings/Views/SettingsMainView.axaml index 4958c2476..4292005c5 100644 --- a/SnapX.Avalonia/Views/Settings/Views/SettingsMainView.axaml +++ b/SnapX.Avalonia/Views/Settings/Views/SettingsMainView.axaml @@ -3,18 +3,18 @@ d:DesignWidth="800" mc:Ignorable="d" x:Class="SnapX.Avalonia.Views.Settings.Views.SettingsMainView" - x:DataType="viewModels1:SettingsMainViewVM" + x:DataType="viewModels:SettingsMainViewVM" xmlns="https://github.com/avaloniaui" xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:core="clr-namespace:SnapX.Core;assembly=SnapX.Core" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:fluent="clr-namespace:FluentIcons.Avalonia.Fluent;assembly=FluentIcons.Avalonia.Fluent" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:viewModels1="clr-namespace:SnapX.Avalonia.ViewModels" xmlns:views="clr-namespace:SnapX.Avalonia.Views.Settings.Views" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:viewModels="clr-namespace:SnapX.CommonUI.ViewModels;assembly=SnapX.CommonUI"> - + true snapx SnapX CLI + SnapX.CLI.Tests diff --git a/SnapX.CommonUI/Changelog.cs b/SnapX.CommonUI/Changelog.cs index 3e39940f0..a7f7fcbad 100644 --- a/SnapX.CommonUI/Changelog.cs +++ b/SnapX.CommonUI/Changelog.cs @@ -21,17 +21,18 @@ internal partial class ChangelogContext : JsonSerializerContext; public abstract class Changelog { private static readonly HttpClient Client = HttpClientFactory.Get(); - public string Version { get; init; } - public Version versionSemver; - public int major; - public int minor; - public int patch; + protected string Version { get; init; } + private readonly Version versionSemver; + private readonly int major; + private readonly int minor; + private readonly int patch; - public JsonSerializerOptions Options = new() + private readonly JsonSerializerOptions Options = new() { TypeInfoResolver = ChangelogContext.Default }; - public Changelog(string version) + + protected Changelog(string version) { Version = version; versionSemver = new Version(version); @@ -42,8 +43,8 @@ public Changelog(string version) public record ChangelogVersion { - public string Version { get; set; } - public string Content { get; set; } + public string Version { get; set; } = "0.0.0"; + public string Content { get; set; } = ""; } public virtual async Task GetChangeSummary() { @@ -78,7 +79,7 @@ private bool IsValidChangelog(string changelog) return false; } #if DEBUG - DebugHelper.WriteLine($"Validating changelog: {changelog?.Substring(0, Math.Min(100, changelog.Length))}..."); + DebugHelper.WriteLine($"Validating changelog: {changelog[..Math.Min(100, changelog.Length)]}..."); #endif return changelog!.Length > 4; } @@ -158,7 +159,7 @@ private async Task GetTagsSinceVersion() }) .Select(tag => { - var firstLineOfMessage = tag.Commit?.Message?.Split('\n').FirstOrDefault()?.Trim(); + var firstLineOfMessage = tag.Commit?.Message.Split('\n').FirstOrDefault()?.Trim(); return $"Tag: {tag.Name} - {firstLineOfMessage}"; }) .ToList(); @@ -180,7 +181,7 @@ private async Task GetBuildSummaryFromActions() return string.Empty; var buildSummaries = actions.WorkflowRuns - .Where(run => (run?.RunNumber > patch) && (run.Name.Contains("build", StringComparison.OrdinalIgnoreCase)) && run.Status.Contains("success", StringComparison.InvariantCultureIgnoreCase)) + .Where(run => run.RunNumber > patch && (run.Name.Contains("build", StringComparison.OrdinalIgnoreCase)) && run.Status.Contains("success", StringComparison.InvariantCultureIgnoreCase)) .Select(run => $"{run.Name} #{run.RunNumber}: {run.DisplayTitle} - {run.Actor.Login}") .ToList(); @@ -234,13 +235,12 @@ private async Task GetRecentCommits() /// Defaults to splitting on two or more consecutive newline sequences. /// /// An enumerable of individual changelog entries. - /// Thrown if changelogs is null. + /// Thrown if changelogs are null. public static IEnumerable SeparateChangelogEntries( IEnumerable changelogs, string? pattern = null) { - if (changelogs == null) - throw new ArgumentNullException(nameof(changelogs)); + ArgumentNullException.ThrowIfNull(changelogs); // Default pattern for separating traditional multi-line changelog entries pattern ??= @"(?:\r?\n){2,}"; diff --git a/SnapX.Avalonia/Models/ListItemTemplate.cs b/SnapX.CommonUI/Models/ListItemTemplate.cs similarity index 68% rename from SnapX.Avalonia/Models/ListItemTemplate.cs rename to SnapX.CommonUI/Models/ListItemTemplate.cs index e5052b228..886b05d28 100644 --- a/SnapX.Avalonia/Models/ListItemTemplate.cs +++ b/SnapX.CommonUI/Models/ListItemTemplate.cs @@ -1,3 +1,3 @@ -namespace SnapX.Avalonia.Models; +namespace SnapX.CommonUI.Models; public record ListItemTemplate(Type ModelType, string IconKey, string Label); diff --git a/SnapX.Avalonia/Models/ListTaskTemplate.cs b/SnapX.CommonUI/Models/ListTaskTemplate.cs similarity index 74% rename from SnapX.Avalonia/Models/ListTaskTemplate.cs rename to SnapX.CommonUI/Models/ListTaskTemplate.cs index e1c2fd307..73b2f7eff 100644 --- a/SnapX.Avalonia/Models/ListTaskTemplate.cs +++ b/SnapX.CommonUI/Models/ListTaskTemplate.cs @@ -1,5 +1,5 @@ using SnapX.Core.History; -namespace SnapX.Avalonia.Models; +namespace SnapX.CommonUI.Models; public record ListTaskTemplate(Type ModelType, HistoryItem task); diff --git a/SnapX.CommonUI/SnapX.CommonUI.csproj b/SnapX.CommonUI/SnapX.CommonUI.csproj index 9f2367792..4e84d305d 100644 --- a/SnapX.CommonUI/SnapX.CommonUI.csproj +++ b/SnapX.CommonUI/SnapX.CommonUI.csproj @@ -9,5 +9,6 @@ + diff --git a/SnapX.CommonUI/TaskThumbnailView.cs b/SnapX.CommonUI/TaskThumbnailView.cs index 2696445c1..af5bdc35d 100644 --- a/SnapX.CommonUI/TaskThumbnailView.cs +++ b/SnapX.CommonUI/TaskThumbnailView.cs @@ -57,7 +57,7 @@ private Image CreateThumbnail(string? filePath = null, Image? img = null) if (img != null) return ImageHelpers.ResizeImage(img, ThumbnailSize, false); if (string.IsNullOrWhiteSpace(filePath)) filePath = Task.Info.FileName; else if (File.Exists(filePath)) return ImageHelpers.ResizeImage(Image.Load(filePath), ThumbnailSize, true); - if (string.IsNullOrEmpty(filePath)) return null; // TODO: Embed error image + if (string.IsNullOrEmpty(filePath)) return Image.Load([]); // TODO: Embed error image var icon = Methods.GetJumboFileIcon(filePath, false); return ImageHelpers.ResizeImage(icon, ThumbnailSize, false, true); } diff --git a/SnapX.CommonUI/Types/CommitTypes.cs b/SnapX.CommonUI/Types/CommitTypes.cs index 7a6375af0..988643902 100644 --- a/SnapX.CommonUI/Types/CommitTypes.cs +++ b/SnapX.CommonUI/Types/CommitTypes.cs @@ -32,13 +32,13 @@ public record Author( ); public record Commit( - [property: JsonPropertyName("author")] Author Author, - [property: JsonPropertyName("committer")] Committer Committer, + [property: JsonPropertyName("author")] Author? Author, + [property: JsonPropertyName("committer")] Committer? Committer, [property: JsonPropertyName("message")] string Message, - [property: JsonPropertyName("tree")] Tree Tree, + [property: JsonPropertyName("tree")] Tree? Tree, [property: JsonPropertyName("html_url")] string Url, [property: JsonPropertyName("comment_count")] int? CommentCount, - [property: JsonPropertyName("verification")] Verification Verification + [property: JsonPropertyName("verification")] Verification? Verification ); public record Committer( @@ -75,13 +75,13 @@ public record Parent( public record Root( [property: JsonPropertyName("sha")] string Sha, [property: JsonPropertyName("node_id")] string NodeId, - [property: JsonPropertyName("commit")] Commit Commit, + [property: JsonPropertyName("commit")] Commit? Commit, [property: JsonPropertyName("url")] string Url, [property: JsonPropertyName("html_url")] string HtmlUrl, [property: JsonPropertyName("comments_url")] string CommentsUrl, - [property: JsonPropertyName("author")] Author Author, - [property: JsonPropertyName("committer")] Committer Committer, - [property: JsonPropertyName("parents")] IReadOnlyList Parents + [property: JsonPropertyName("author")] Author? Author, + [property: JsonPropertyName("committer")] Committer? Committer, + [property: JsonPropertyName("parents")] IReadOnlyList? Parents ); diff --git a/SnapX.CommonUI/Types/TagTypes.cs b/SnapX.CommonUI/Types/TagTypes.cs index f14e3b71b..b28547f72 100644 --- a/SnapX.CommonUI/Types/TagTypes.cs +++ b/SnapX.CommonUI/Types/TagTypes.cs @@ -8,6 +8,6 @@ public record Tag( [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("zipball_url")] string ZipballUrl, [property: JsonPropertyName("tarball_url")] string TarballUrl, - [property: JsonPropertyName("commit")] Commit Commit, + [property: JsonPropertyName("commit")] Commit? Commit, [property: JsonPropertyName("node_id")] string NodeId ); diff --git a/SnapX.Avalonia/ViewModels/AboutWindowViewModel.cs b/SnapX.CommonUI/ViewModels/AboutWindowViewModel.cs similarity index 71% rename from SnapX.Avalonia/ViewModels/AboutWindowViewModel.cs rename to SnapX.CommonUI/ViewModels/AboutWindowViewModel.cs index aa1e9c0d7..0382d98a9 100644 --- a/SnapX.Avalonia/ViewModels/AboutWindowViewModel.cs +++ b/SnapX.CommonUI/ViewModels/AboutWindowViewModel.cs @@ -1,16 +1,15 @@ using System.Diagnostics.CodeAnalysis; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using SnapX.CommonUI; using SnapX.Core.Utils; using SnapX.Core.Utils.Miscellaneous; -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public partial class AboutWindowViewModel : ViewModelBase { // Internal instance of the base class (SnapX.CommonUI.AboutDialog) - private AboutDialog _commonAboutDialog = new(); + private readonly AboutDialog _commonAboutDialog = new(); [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", @@ -18,12 +17,11 @@ public partial class AboutWindowViewModel : ViewModelBase RelayCommand] private Task InitDataAsync() { - var combinedLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies() - .Concat(App.SnapX.GetAssemblies()) - .Distinct(); + var combinedLoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); LoadedAssemblies = string.Join(Environment.NewLine, combinedLoadedAssemblies .Where(a => a.GetName().Name != null) .Where(a => +#pragma warning disable CS8602 // Dereference of a possibly null reference. !a.GetName().Name.StartsWith("System") && !a.GetName().Name.StartsWith("SnapX", StringComparison.OrdinalIgnoreCase) && !a.GetName().Name.StartsWith("Anonymous", StringComparison.OrdinalIgnoreCase) && @@ -40,8 +38,10 @@ private Task InitDataAsync() .Select(g => g.Count() > 1 ? $"{g.Key} {g.First().Version.Major}.{g.First().Version.Minor}.{g.First().Version.Build}" : $"{g.First().Name} {g.First().Version.Major}.{g.First().Version.Minor}.{g.First().Version.Build}") - .Append($"SQLite {Core.SnapX.DbConnection.ServerVersion}") + .Append($"SQLite {Core.SnapX.DbConnection?.ServerVersion}") .OrderBy(name => name)); +#pragma warning restore CS8602 // Dereference of a possibly null reference. + Description = _commonAboutDialog.GetDescription(); Version = _commonAboutDialog.GetVersion(); Copyright = _commonAboutDialog.GetCopyright(); @@ -59,48 +59,21 @@ private Task InitDataAsync() SystemInformationText = $"{SystemInfo} ({OsArchitecture}, {OsPlatform}) powered by {Runtime}!"; return Task.CompletedTask; } - [ObservableProperty] - public string dialogTitle = Lang.AboutSnapX; - [ObservableProperty] - private string? description; - [ObservableProperty] - public string? buildInformation; - [ObservableProperty] - - public string? version; - [ObservableProperty] - public string? copyright; - [ObservableProperty] - - public string? license; - [ObservableProperty] - - public string? website; - [ObservableProperty] - - public string? systemInfo; - [ObservableProperty] - - public string? osArchitecture; - [ObservableProperty] - - public string? runtime; - [ObservableProperty] - - public string? osPlatform; - [ObservableProperty] - - public string? documentation; - [ObservableProperty] - - public string? issues; - [ObservableProperty] - public string? discord; - [ObservableProperty] - public string? donate; - [ObservableProperty] - public string? loadedAssemblies; - - [ObservableProperty] - public string? systemInformationText; + [ObservableProperty] private string dialogTitle = Lang.AboutSnapX; + [ObservableProperty] private string? description; + [ObservableProperty] private string? buildInformation; + [ObservableProperty] private string? version; + [ObservableProperty] private string? copyright; + [ObservableProperty] private string? license; + [ObservableProperty] private string? website; + [ObservableProperty] private string? systemInfo; + [ObservableProperty] private string? osArchitecture; + [ObservableProperty] private string? runtime; + [ObservableProperty] private string? osPlatform; + [ObservableProperty] private string? documentation; + [ObservableProperty] private string? issues; + [ObservableProperty] private string? discord; + [ObservableProperty] private string? donate; + [ObservableProperty] private string? loadedAssemblies; + [ObservableProperty] private string? systemInformationText; } diff --git a/SnapX.Avalonia/ViewModels/AvaloniaChangelog.cs b/SnapX.CommonUI/ViewModels/AvaloniaChangelog.cs similarity index 89% rename from SnapX.Avalonia/ViewModels/AvaloniaChangelog.cs rename to SnapX.CommonUI/ViewModels/AvaloniaChangelog.cs index 19360251d..92c32c2c5 100644 --- a/SnapX.Avalonia/ViewModels/AvaloniaChangelog.cs +++ b/SnapX.CommonUI/ViewModels/AvaloniaChangelog.cs @@ -1,4 +1,4 @@ -namespace SnapX.Avalonia; +namespace SnapX.CommonUI.ViewModels; public class AvaloniaChangelog : SnapX.CommonUI.Changelog { diff --git a/SnapX.Avalonia/ViewModels/ChangelogViewModel.cs b/SnapX.CommonUI/ViewModels/ChangelogViewModel.cs similarity index 85% rename from SnapX.Avalonia/ViewModels/ChangelogViewModel.cs rename to SnapX.CommonUI/ViewModels/ChangelogViewModel.cs index 633d13885..0526cab1e 100644 --- a/SnapX.Avalonia/ViewModels/ChangelogViewModel.cs +++ b/SnapX.CommonUI/ViewModels/ChangelogViewModel.cs @@ -1,14 +1,13 @@ -using Avalonia.Collections; +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; -using SnapX.CommonUI; using SnapX.Core.Utils; -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public partial class ChangelogViewModel : ViewModelBase { - public AvaloniaList Versions { get; } = []; + public ObservableCollection Versions { get; } = []; [ObservableProperty] public Changelog.ChangelogVersion selectedChangelogVersion = new(); diff --git a/SnapX.Avalonia/ViewModels/OCRViewModel.cs b/SnapX.CommonUI/ViewModels/OCRViewModel.cs similarity index 98% rename from SnapX.Avalonia/ViewModels/OCRViewModel.cs rename to SnapX.CommonUI/ViewModels/OCRViewModel.cs index de9742e19..f014cd0de 100644 --- a/SnapX.Avalonia/ViewModels/OCRViewModel.cs +++ b/SnapX.CommonUI/ViewModels/OCRViewModel.cs @@ -5,7 +5,7 @@ using SnapX.Core.Utils; using Image = SixLabors.ImageSharp.Image; -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public partial class OCRViewModel : ViewModelBase { diff --git a/SnapX.Avalonia/ViewModels/RegionSelectorViewModel.cs b/SnapX.CommonUI/ViewModels/RegionSelectorViewModel.cs similarity index 81% rename from SnapX.Avalonia/ViewModels/RegionSelectorViewModel.cs rename to SnapX.CommonUI/ViewModels/RegionSelectorViewModel.cs index cc8ec1f88..a2b91578b 100644 --- a/SnapX.Avalonia/ViewModels/RegionSelectorViewModel.cs +++ b/SnapX.CommonUI/ViewModels/RegionSelectorViewModel.cs @@ -1,4 +1,4 @@ -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public partial class RegionSelectorViewModel : ViewModelBase { private int Width; diff --git a/SnapX.Avalonia/ViewModels/SettingsHomePageViewVM.cs b/SnapX.CommonUI/ViewModels/SettingsHomePageViewVM.cs similarity index 61% rename from SnapX.Avalonia/ViewModels/SettingsHomePageViewVM.cs rename to SnapX.CommonUI/ViewModels/SettingsHomePageViewVM.cs index e6823e461..2b22bc0e2 100644 --- a/SnapX.Avalonia/ViewModels/SettingsHomePageViewVM.cs +++ b/SnapX.CommonUI/ViewModels/SettingsHomePageViewVM.cs @@ -1,4 +1,4 @@ -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public class SettingsHomePageViewVM : ViewModelBase { diff --git a/SnapX.Avalonia/ViewModels/SettingsMainViewVM.cs b/SnapX.CommonUI/ViewModels/SettingsMainViewVM.cs similarity index 65% rename from SnapX.Avalonia/ViewModels/SettingsMainViewVM.cs rename to SnapX.CommonUI/ViewModels/SettingsMainViewVM.cs index 9745f5492..d1b82b018 100644 --- a/SnapX.Avalonia/ViewModels/SettingsMainViewVM.cs +++ b/SnapX.CommonUI/ViewModels/SettingsMainViewVM.cs @@ -1,10 +1,9 @@ -using Avalonia.Collections; -using Avalonia.Controls; +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.DependencyInjection; -using SnapX.Avalonia.Models; +using SnapX.CommonUI.Models; -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public partial class SettingsMainViewVM : ViewModelBase { @@ -15,23 +14,19 @@ public partial class SettingsMainViewVM : ViewModelBase private ViewModelBase _currentPage = new SettingsHomePageViewVM(); [ObservableProperty] private ListItemTemplate? _selectedListItem; - public AvaloniaList Items { get; } + public ObservableCollection Items { get; } public SettingsMainViewVM() { _currentPage = new SettingsHomePageViewVM(); - Items = new AvaloniaList(_templates); + Items = new ObservableCollection(_templates); SelectedListItem = Items.First(vm => vm.ModelType == typeof(SettingsHomePageViewVM)); } partial void OnSelectedListItemChanged(ListItemTemplate? value) { if (value is null) return; -#pragma warning disable IL2072 // The code works, leave me alone - var vm = Design.IsDesignMode - ? Activator.CreateInstance(value.ModelType) - : Ioc.Default.GetService(value.ModelType); -#pragma warning restore IL2072 + var vm = Ioc.Default.GetService(value.ModelType); if (vm is not ViewModelBase vmb) return; diff --git a/SnapX.Avalonia/ViewModels/ViewModelBase.cs b/SnapX.CommonUI/ViewModels/ViewModelBase.cs similarity index 72% rename from SnapX.Avalonia/ViewModels/ViewModelBase.cs rename to SnapX.CommonUI/ViewModels/ViewModelBase.cs index eafcb5e39..2790b058c 100644 --- a/SnapX.Avalonia/ViewModels/ViewModelBase.cs +++ b/SnapX.CommonUI/ViewModels/ViewModelBase.cs @@ -1,5 +1,5 @@ using CommunityToolkit.Mvvm.ComponentModel; -namespace SnapX.Avalonia.ViewModels; +namespace SnapX.CommonUI.ViewModels; public class ViewModelBase : ObservableObject; diff --git a/SnapX.Core/ApplicationConfig.cs b/SnapX.Core/ApplicationConfig.cs index f61473933..741e93c4a 100644 --- a/SnapX.Core/ApplicationConfig.cs +++ b/SnapX.Core/ApplicationConfig.cs @@ -1,179 +1,21 @@ using System.ComponentModel; using SixLabors.ImageSharp; using SnapX.Core.History; +using SnapX.Core.ImageEffects; using SnapX.Core.Job; using SnapX.Core.Utils; using SnapX.Core.Utils.Miscellaneous; namespace SnapX.Core; -public class GradientColor +public class ApplicationConfig { - public string Color { get; set; } - public double Location { get; set; } -} - -public class PinToScreenOptions -{ - public int InitialScale { get; set; } - public int ScaleStep { get; set; } - public bool HighQualityScale { get; set; } - public int InitialOpacity { get; set; } - public int OpacityStep { get; set; } - public string Placement { get; set; } - public int PlacementOffset { get; set; } - public bool TopMost { get; set; } - public bool KeepCenterLocation { get; set; } - public string BackgroundColor { get; set; } - public bool Shadow { get; set; } - public bool Border { get; set; } - public int BorderSize { get; set; } - public string BorderColor { get; set; } - public string MinimizeSize { get; set; } -} - -public class ImageBeautifierOptions -{ - public int Margin { get; set; } - public int Padding { get; set; } - public bool SmartPadding { get; set; } - public int RoundedCorner { get; set; } - public int ShadowRadius { get; set; } - public int ShadowOpacity { get; set; } - public int ShadowDistance { get; set; } - public int ShadowAngle { get; set; } - public string ShadowColor { get; set; } - public string BackgroundType { get; set; } - public BackgroundGradient BackgroundGradient { get; set; } - public string BackgroundColor { get; set; } - public string BackgroundImageFilePath { get; set; } -} - -public class BackgroundGradient -{ - public string Type { get; set; } - public List Colors { get; set; } -} - -public class ImageCombinerOptions -{ - public string Orientation { get; set; } - public string Alignment { get; set; } - public int Space { get; set; } - public int WrapAfter { get; set; } - public bool AutoFillBackground { get; set; } -} - -public class VideoConverterOptions -{ - public string InputFilePath { get; set; } - public string OutputFolderPath { get; set; } - public string OutputFileName { get; set; } - public string VideoCodec { get; set; } - public int VideoQuality { get; set; } - public bool VideoQualityUseBitrate { get; set; } - public int VideoQualityBitrate { get; set; } - public bool UseCustomArguments { get; set; } - public string CustomArguments { get; set; } - public bool AutoOpenFolder { get; set; } -} - -public class VideoThumbnailOptions -{ - public string DefaultOutputDirectory { get; set; } - public string LastVideoPath { get; set; } - public string OutputLocation { get; set; } - public string CustomOutputDirectory { get; set; } - public string ImageFormat { get; set; } - public int ThumbnailCount { get; set; } - public string FilenameSuffix { get; set; } - public bool RandomFrame { get; set; } - public bool UploadThumbnails { get; set; } - public bool KeepScreenshots { get; set; } - public bool OpenDirectory { get; set; } - public int MaxThumbnailWidth { get; set; } - public bool CombineScreenshots { get; set; } - public int Padding { get; set; } - public int Spacing { get; set; } - public int ColumnCount { get; set; } - public bool AddVideoInfo { get; set; } - public bool AddTimestamp { get; set; } - public bool DrawShadow { get; set; } - public bool DrawBorder { get; set; } -} - -public class BorderlessWindowSettings -{ - public bool RememberWindowTitle { get; set; } - public string WindowTitle { get; set; } - public bool AutoCloseWindow { get; set; } - public bool ExcludeTaskbarArea { get; set; } -} - -public class QuickTaskPreset -{ - public string Name { get; set; } - public List AfterCaptureTasks { get; set; } - public List AfterUploadTasks { get; set; } -} - -public class Theme -{ - public string Name { get; set; } - public string BackgroundColor { get; set; } - public string LightBackgroundColor { get; set; } - public string DarkBackgroundColor { get; set; } - public string TextColor { get; set; } - public string BorderColor { get; set; } - public string CheckerColor { get; set; } - public string CheckerColor2 { get; set; } - public int CheckerSize { get; set; } - public string LinkColor { get; set; } - public string MenuHighlightColor { get; set; } - public string MenuHighlightBorderColor { get; set; } - public string MenuBorderColor { get; set; } - public string MenuCheckBackgroundColor { get; set; } - public string MenuFont { get; set; } - public string ContextMenuFont { get; set; } - public int ContextMenuOpacity { get; set; } - public string SeparatorLightColor { get; set; } - public string SeparatorDarkColor { get; set; } -} - -public class ProxySettings -{ - public string ProxyMethod { get; set; } - public string Host { get; set; } - public int Port { get; set; } - public string Username { get; set; } - public string Password { get; set; } -} - -public class WindowState -{ - public string Location { get; set; } - public string Size { get; set; } - public bool IsMaximized { get; set; } -} - -public class ImageHistorySettings -{ - public bool RememberWindowState { get; set; } - public WindowState WindowState { get; set; } - public string ThumbnailSize { get; set; } - public int MaxItemCount { get; set; } - public bool FilterMissingFiles { get; set; } - public bool RememberSearchText { get; set; } - public string SearchText { get; set; } -} - -public class RootConfiguration -{ - public TaskSettings DefaultTaskSettings = TaskSettings.GetDefaultTaskSettings(); + public TaskSettings? DefaultTaskSettings = TaskSettings.GetDefaultTaskSettings(); public DateTime FirstTimeRunDate = DateTime.Now; public string FileUploadDefaultDirectory = ""; public int NameParserAutoIncrementNumber = 0; - public List QuickTaskPresets = []; + + public List QuickTaskPresets = QuickTaskInfo.DefaultPresets; // Main window public bool FirstTimeMinimizeToTray = true; public List TaskListViewColumnWidths = []; @@ -196,8 +38,8 @@ public class RootConfiguration // TEMP: For backward compatibility public bool CheckPreReleaseUpdates = false; public bool UseCustomTheme { get; set; } - public List Themes { get; set; } - public int SelectedTheme { get; set; } + public List Themes { get; set; } = Theme.GetDefaultThemes(); + public int SelectedTheme { get; set; } = 0; public bool UseCustomScreenshotsPath = false; public string? CustomScreenshotsPath = ""; public string? SaveImageSubFolderPattern = "%y-%mo"; @@ -224,7 +66,6 @@ public class RootConfiguration public List SecondaryFileUploaders = []; public bool HistorySaveTasks = true; public bool HistoryCheckURL = false; - public List RecentTasks { get; set; } public bool RecentTasksSave = false; public int RecentTasksMaxCount = 10; public bool RecentTasksShowInMainWindow = true; @@ -306,14 +147,8 @@ public bool DevMode [Category("Hotkey"), DefaultValue(500), Description("If you hold hotkeys then it will only trigger every this milliseconds.")] public int HotkeyRepeatLimit { - get - { - return hotkeyRepeatLimit; - } - set - { - hotkeyRepeatLimit = Math.Max(value, 200); - } + get => hotkeyRepeatLimit; + set => hotkeyRepeatLimit = Math.Max(value, 200); } [Category("Clipboard"), DefaultValue(true), Description("Show clipboard content viewer when using clipboard upload in main window.")] public bool ShowClipboardContentViewer { get; set; } @@ -362,10 +197,9 @@ public int HotkeyRepeatLimit [Category("Drag and drop window"), DefaultValue(255), Description("When you drag file to drop window then opacity will change to this.")] public int DropHoverOpacity { get; set; } - // [Category("Drag and drop window"), DefaultValue(ContentAlignment.BottomRight), Description("Where drop window will open.")] - // public ContentAlignment DropAlignment { get; set; } + [Category("Drag and drop window"), DefaultValue(ContentAlignment.BottomRight), Description("Where drop window will open.")] + public ContentAlignment DropAlignment { get; set; } public string ApplicationVersion { get; set; } = Helpers.GetApplicationVersion(); - public string? SQLitePath { get; set; } } diff --git a/SnapX.Core/CLI/CLICommand.cs b/SnapX.Core/CLI/CLICommand.cs index 38034bbe3..515f0c381 100644 --- a/SnapX.Core/CLI/CLICommand.cs +++ b/SnapX.Core/CLI/CLICommand.cs @@ -1,20 +1,13 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.CLI; -public class CLICommand +public record CLICommand(string? Command = null, string? Parameter = null) { - public string? Command { get; set; } - public string? Parameter { get; set; } + public string? Command { get; set; } = Command; + public string? Parameter { get; set; } = Parameter; public bool IsCommand { get; set; } // Starts with hyphen? - public CLICommand(string? command = null, string? parameter = null) - { - Command = command; - Parameter = parameter; - } - public bool CheckCommand(string command, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase) { return !string.IsNullOrEmpty(Command) && Command.Equals(command, comparisonType); @@ -22,7 +15,7 @@ public bool CheckCommand(string command, StringComparison comparisonType = Strin public override string? ToString() { - string? text = ""; + var text = ""; if (IsCommand) { diff --git a/SnapX.Core/CLI/CLICommandAction.cs b/SnapX.Core/CLI/CLICommandAction.cs index f2812bf04..154ef8b7b 100644 --- a/SnapX.Core/CLI/CLICommandAction.cs +++ b/SnapX.Core/CLI/CLICommandAction.cs @@ -1,20 +1,14 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.CLI; -public class CLICommandAction +public record CLICommandAction(params string[] Commands) { - public string[] Commands; + public string[] Commands = Commands; public Action DefaultAction; public Action TextAction; public Action NumberAction; - public CLICommandAction(params string[] commands) - { - Commands = commands; - } - public bool CheckCommands(List commands) { foreach (CLICommand command in commands) diff --git a/SnapX.Core/CLI/CLIManager.cs b/SnapX.Core/CLI/CLIManager.cs index 43af96297..d25ae4a5f 100644 --- a/SnapX.Core/CLI/CLIManager.cs +++ b/SnapX.Core/CLI/CLIManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/CLI/ExternalCLIManager.cs b/SnapX.Core/CLI/ExternalCLIManager.cs index 862c1402c..ed66914c4 100644 --- a/SnapX.Core/CLI/ExternalCLIManager.cs +++ b/SnapX.Core/CLI/ExternalCLIManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -13,54 +12,51 @@ public abstract class ExternalCLIManager : IDisposable public bool IsProcessRunning { get; private set; } - protected Process process; + protected Process? process; - public virtual int Open(string? path, string args = null) + public virtual int Open(string? path, string? args = null) { - if (System.IO.File.Exists(path)) + if (!File.Exists(path)) return -1; + using (process = new Process()) { - using (process = new Process()) + var psi = new ProcessStartInfo + { + FileName = path, + WorkingDirectory = Path.GetDirectoryName(path), + Arguments = args, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8 + }; + + process.EnableRaisingEvents = true; + if (psi.RedirectStandardOutput) process.OutputDataReceived += cli_OutputDataReceived; + if (psi.RedirectStandardError) process.ErrorDataReceived += cli_ErrorDataReceived; + process.StartInfo = psi; + + Console.WriteLine($"CLI: \"{psi.FileName}\" {psi.Arguments}"); + process.Start(); + + if (psi.RedirectStandardOutput) process.BeginOutputReadLine(); + if (psi.RedirectStandardError) process.BeginErrorReadLine(); + + try + { + IsProcessRunning = true; + process.WaitForExit(); + } + finally { - ProcessStartInfo psi = new ProcessStartInfo() - { - FileName = path, - WorkingDirectory = Path.GetDirectoryName(path), - Arguments = args, - UseShellExecute = false, - CreateNoWindow = true, - RedirectStandardInput = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - StandardOutputEncoding = Encoding.UTF8, - StandardErrorEncoding = Encoding.UTF8 - }; - - process.EnableRaisingEvents = true; - if (psi.RedirectStandardOutput) process.OutputDataReceived += cli_OutputDataReceived; - if (psi.RedirectStandardError) process.ErrorDataReceived += cli_ErrorDataReceived; - process.StartInfo = psi; - - Console.WriteLine($"CLI: \"{psi.FileName}\" {psi.Arguments}"); - process.Start(); - - if (psi.RedirectStandardOutput) process.BeginOutputReadLine(); - if (psi.RedirectStandardError) process.BeginErrorReadLine(); - - try - { - IsProcessRunning = true; - process.WaitForExit(); - } - finally - { - IsProcessRunning = false; - } - - return process.ExitCode; + IsProcessRunning = false; } + + return process.ExitCode; } - return -1; } private void cli_OutputDataReceived(object sender, DataReceivedEventArgs e) @@ -81,7 +77,7 @@ private void cli_ErrorDataReceived(object sender, DataReceivedEventArgs e) public void WriteInput(string input) { - if (IsProcessRunning && process != null && process.StartInfo != null && process.StartInfo.RedirectStandardInput) + if (IsProcessRunning && process is { StartInfo.RedirectStandardInput: true }) { process.StandardInput.WriteLine(input); } @@ -97,10 +93,8 @@ public virtual void Close() public void Dispose() { - if (process != null) - { - process.Dispose(); - } + process?.Dispose(); + GC.SuppressFinalize(this); } } diff --git a/SnapX.Core/CLI/NativeMessageInput.cs b/SnapX.Core/CLI/NativeMessageInput.cs index e9254179f..d4d366ada 100644 --- a/SnapX.Core/CLI/NativeMessageInput.cs +++ b/SnapX.Core/CLI/NativeMessageInput.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.CLI; -public class NativeMessagingInput +public record NativeMessagingInput { public NativeMessagingAction Action { get; set; } public string? URL { get; set; } diff --git a/SnapX.Core/CLI/NativeMessagingHost.cs b/SnapX.Core/CLI/NativeMessagingHost.cs index bec8e1094..4625f630b 100644 --- a/SnapX.Core/CLI/NativeMessagingHost.cs +++ b/SnapX.Core/CLI/NativeMessagingHost.cs @@ -1,38 +1,35 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Text; namespace SnapX.Core.CLI; -public class NativeMessagingHost +public record NativeMessagingHost { public string Read() { - string input = null; + var input = ""; - Stream inputStream = Console.OpenStandardInput(); + var inputStream = Console.OpenStandardInput(); - byte[] bytesLength = new byte[4]; + var bytesLength = new byte[4]; inputStream.ReadExactly(bytesLength); - int inputLength = BitConverter.ToInt32(bytesLength, 0); + var inputLength = BitConverter.ToInt32(bytesLength, 0); - if (inputLength > 0) - { - byte[] bytesInput = new byte[inputLength]; - inputStream.ReadExactly(bytesInput); - input = Encoding.UTF8.GetString(bytesInput); - } + if (inputLength <= 0) return input; + var bytesInput = new byte[inputLength]; + inputStream.ReadExactly(bytesInput); + input = Encoding.UTF8.GetString(bytesInput); return input; } public void Write(string data) { - Stream outputStream = Console.OpenStandardOutput(); + var outputStream = Console.OpenStandardOutput(); - byte[] bytesData = Encoding.UTF8.GetBytes(data); - byte[] bytesLength = BitConverter.GetBytes(bytesData.Length); + var bytesData = Encoding.UTF8.GetBytes(data); + var bytesLength = BitConverter.GetBytes(bytesData.Length); outputStream.Write(bytesLength, 0, bytesLength.Length); diff --git a/SnapX.Core/CLI/SnapXCLIManager.cs b/SnapX.Core/CLI/SnapXCLIManager.cs index f0d9ef269..5820fe9c9 100644 --- a/SnapX.Core/CLI/SnapXCLIManager.cs +++ b/SnapX.Core/CLI/SnapXCLIManager.cs @@ -5,21 +5,17 @@ namespace SnapX.Core.CLI; -public class SnapXCLIManager : CLIManager +public class SnapXCLIManager(string?[] Arguments) : CLIManager(Arguments) { - public SnapXCLIManager(string?[] arguments) : base(arguments) - { - } - public async Task UseCommandLineArgs() => UseCommandLineArgs(Commands); public async Task UseCommandLineArgs(List commands) { - if (commands != null && commands.Count > 0) + if (commands is { Count: > 0 }) { - TaskSettings taskSettings = FindCLITask(commands); + var taskSettings = FindCLITask(commands); - foreach (CLICommand command in commands) + foreach (var command in commands) { if (command.IsCommand) @@ -45,25 +41,12 @@ await CheckNativeMessagingInput(command)) } } - private TaskSettings FindCLITask(List commands) + private TaskSettings? FindCLITask(List commands) { - if (SnapX.HotkeysConfig != null) - { - CLICommand command = commands.FirstOrDefault(x => x.CheckCommand("task") && !string.IsNullOrEmpty(x.Parameter)); - - if (command != null) - { - foreach (HotkeySettings hotkeySetting in SnapX.HotkeysConfig.Hotkeys) - { - if (command.Parameter == hotkeySetting.TaskSettings.ToString()) - { - return TaskSettings.GetSafeTaskSettings(hotkeySetting.TaskSettings); - } - } - } - } + if (SnapX.HotkeysConfig == null) return null; + var command = commands.FirstOrDefault(x => x.CheckCommand("task") && !string.IsNullOrEmpty(x.Parameter)); - return null; + return command == null ? null : (from hotkeySetting in SnapX.HotkeysConfig.Hotkeys where command.Parameter == hotkeySetting.TaskSettings.ToString() select TaskSettings.GetSafeTaskSettings(hotkeySetting.TaskSettings)).FirstOrDefault(); } private bool CheckCustomUploader(CLICommand command) diff --git a/SnapX.Core/Capture/CaptureActiveMonitor.cs b/SnapX.Core/Capture/CaptureActiveMonitor.cs deleted file mode 100644 index 5048d21b1..000000000 --- a/SnapX.Core/Capture/CaptureActiveMonitor.cs +++ /dev/null @@ -1,22 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; - -public class CaptureActiveMonitor : CaptureBase -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - DebugHelper.WriteLine("CaptureActiveMonitor started"); - var promise = TaskHelpers.GetScreenshot(taskSettings).CaptureActiveMonitor(); - promise.Wait(); - var img = promise.Result; - var metadata = CreateMetadata(img.Bounds); - metadata.Image = img; - return metadata; - } -} - diff --git a/SnapX.Core/Capture/CaptureActiveWindow.cs b/SnapX.Core/Capture/CaptureActiveWindow.cs deleted file mode 100644 index 92dd8d7a8..000000000 --- a/SnapX.Core/Capture/CaptureActiveWindow.cs +++ /dev/null @@ -1,25 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; -public class CaptureActiveWindow : CaptureBase -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - var metadata = CreateMetadata(); - - if (taskSettings.CaptureSettings.CaptureTransparent && !taskSettings.CaptureSettings.CaptureClientArea) - { - metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureActiveWindowTransparent(); - } - else - { - metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureActiveWindow(); - } - - return metadata; - } -} diff --git a/SnapX.Core/Capture/CaptureBase.cs b/SnapX.Core/Capture/CaptureBase.cs deleted file mode 100644 index ceb1dca8c..000000000 --- a/SnapX.Core/Capture/CaptureBase.cs +++ /dev/null @@ -1,124 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SixLabors.ImageSharp; -using SnapX.Core.Job; -using SnapX.Core.Upload; -using SnapX.Core.Utils.Extensions; -using SnapX.Core.Utils.Native; - -namespace SnapX.Core.Capture; -public abstract class CaptureBase -{ - public bool AllowAutoHideForm { get; set; } = true; - public bool AllowAnnotation { get; set; } = true; - - public void Capture(bool autoHideForm) - { - Capture(null, autoHideForm); - } - - public void Capture(TaskSettings taskSettings = null, bool autoHideForm = false) - { - if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); - - // TODO: Reimplement taskSettings.GeneralSettings.ToastWindowAutoHide - // if (taskSettings.GeneralSettings.ToastWindowAutoHide) - // { - // NotificationForm.CloseActiveForm(); - // } - - if (taskSettings.CaptureSettings.ScreenshotDelay > 0) - { - int delay = (int)(taskSettings.CaptureSettings.ScreenshotDelay * 1000); - - Task.Delay(delay).ContinueInCurrentContext(() => - { - CaptureInternal(taskSettings, autoHideForm); - }); - } - else - { - CaptureInternal(taskSettings, autoHideForm); - } - } - - protected abstract TaskMetadata Execute(TaskSettings taskSettings); - - private void CaptureInternal(TaskSettings taskSettings, bool autoHideForm) - { - if (autoHideForm && AllowAutoHideForm) - { - // SnapX.MainWindow.Hide(); - // Thread.Sleep(250); - } - - TaskMetadata metadata = null; - - try - { - AllowAnnotation = true; - metadata = Execute(taskSettings); - } - catch (Exception ex) - { - DebugHelper.WriteException(ex); - } - finally - { - if (autoHideForm && AllowAutoHideForm) - { - // SnapX.MainWindow.ForceActivate(); - } - - AfterCapture(metadata, taskSettings); - } - } - - private void AfterCapture(TaskMetadata metadata, TaskSettings taskSettings) - { - if (metadata != null && metadata.Image != null) - { - TaskHelpers.PlayNotificationSoundAsync(NotificationSound.Capture, taskSettings); - - if (taskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.AnnotateImage) && !AllowAnnotation) - { - taskSettings.AfterCaptureJob = taskSettings.AfterCaptureJob.Remove(AfterCaptureTasks.AnnotateImage); - } - - if (taskSettings.ImageSettings.ImageEffectOnlyRegionCapture && - GetType() != typeof(CaptureRegion) && GetType() != typeof(CaptureLastRegion)) - { - taskSettings.AfterCaptureJob = taskSettings.AfterCaptureJob.Remove(AfterCaptureTasks.AddImageEffects); - } - - UploadManager.RunImageTask(metadata, taskSettings); - } - } - - protected TaskMetadata CreateMetadata() - { - return CreateMetadata(Rectangle.Empty, null); - } - - protected TaskMetadata CreateMetadata(Rectangle insideRect) - { - return CreateMetadata(insideRect, "explorer"); - } - - protected TaskMetadata CreateMetadata(Rectangle insideRect, string ignoreProcess) - { - var metadata = new TaskMetadata(); - - var windowInfo = Methods.GetForegroundWindow(); - if ((ignoreProcess == null || !windowInfo.ProcessName.Equals(ignoreProcess, StringComparison.OrdinalIgnoreCase)) && - (insideRect.IsEmpty || windowInfo.Rectangle.Contains(insideRect))) - { - metadata.UpdateInfo(windowInfo); - } - - return metadata; - } -} - diff --git a/SnapX.Core/Capture/CaptureCustomRegion.cs b/SnapX.Core/Capture/CaptureCustomRegion.cs deleted file mode 100644 index 712481ca4..000000000 --- a/SnapX.Core/Capture/CaptureCustomRegion.cs +++ /dev/null @@ -1,19 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; - -public class CaptureCustomRegion : CaptureBase -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - var rect = taskSettings.CaptureSettings.CaptureCustomRegion; - var metadata = CreateMetadata(rect); - metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureRectangle(rect); - return metadata; - } -} - diff --git a/SnapX.Core/Capture/CaptureCustomWindow.cs b/SnapX.Core/Capture/CaptureCustomWindow.cs deleted file mode 100644 index 6cafe2558..000000000 --- a/SnapX.Core/Capture/CaptureCustomWindow.cs +++ /dev/null @@ -1,34 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; -public class CaptureCustomWindow : CaptureWindow -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - string windowTitle = taskSettings.CaptureSettings.CaptureCustomWindow; - - if (!string.IsNullOrEmpty(windowTitle)) - { - // TODO: Reimplement w/ Windows support & Linux (X11, and KDE Plasma Wayland) - // IntPtr hWnd = NativeMethods.SearchWindow(windowTitle); - // - // if (hWnd == IntPtr.Zero) - // { - // MessageBox.Show(Resources.UnableToFindAWindowWithSpecifiedWindowTitle, "SnapX", MessageBoxButtons.OK, MessageBoxIcon.Information); - // } - // else - // { - // WindowHandle = hWnd; - // - // return base.Execute(taskSettings); - // } - } - - return null; - } -} - diff --git a/SnapX.Core/Capture/CaptureFullscreen.cs b/SnapX.Core/Capture/CaptureFullscreen.cs deleted file mode 100644 index 9e1e5f8a8..000000000 --- a/SnapX.Core/Capture/CaptureFullscreen.cs +++ /dev/null @@ -1,21 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; - -public class CaptureFullscreen : CaptureBase -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - DebugHelper.WriteLine("CaptureFullscreen"); - var img = TaskHelpers.GetScreenshot(taskSettings).CaptureFullscreen(); - var metadata = CreateMetadata(img.Bounds); - metadata.Image = img; - - return metadata; - } -} - diff --git a/SnapX.Core/Capture/CaptureLastRegion.cs b/SnapX.Core/Capture/CaptureLastRegion.cs deleted file mode 100644 index b99455790..000000000 --- a/SnapX.Core/Capture/CaptureLastRegion.cs +++ /dev/null @@ -1,21 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; -public class CaptureLastRegion : CaptureRegion -{ - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - switch (lastRegionCaptureType) - { - default: - case RegionCaptureType.Default: return ExecuteRegionCapture(taskSettings); - case RegionCaptureType.Light: return ExecuteRegionCaptureLight(taskSettings); - case RegionCaptureType.Transparent: return ExecuteRegionCaptureTransparent(taskSettings); - } - } -} - diff --git a/SnapX.Core/Capture/CaptureMonitor.cs b/SnapX.Core/Capture/CaptureMonitor.cs deleted file mode 100644 index 25ebb0fc4..000000000 --- a/SnapX.Core/Capture/CaptureMonitor.cs +++ /dev/null @@ -1,26 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SixLabors.ImageSharp; -using SnapX.Core.Job; - -namespace SnapX.Core.Capture; -public class CaptureMonitor : CaptureBase -{ - public Rectangle MonitorRectangle { get; private set; } - - public CaptureMonitor(Rectangle monitorRectangle) - { - MonitorRectangle = monitorRectangle; - } - - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - DebugHelper.WriteLine("CaptureMonitor Start"); - var metadata = CreateMetadata(MonitorRectangle); - metadata.Image = TaskHelpers.GetScreenshot().CaptureRectangle(MonitorRectangle); - return metadata; - } -} - diff --git a/SnapX.Core/Capture/CaptureWindow.cs b/SnapX.Core/Capture/CaptureWindow.cs deleted file mode 100644 index b6f0927f6..000000000 --- a/SnapX.Core/Capture/CaptureWindow.cs +++ /dev/null @@ -1,53 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using SnapX.Core.Job; -using SnapX.Core.Media; - -namespace SnapX.Core.Capture; -public class CaptureWindow : CaptureBase -{ - public IntPtr WindowHandle { get; protected set; } - - public CaptureWindow() - { - } - - public CaptureWindow(IntPtr windowHandle) - { - WindowHandle = windowHandle; - } - - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - WindowInfo windowInfo = new(WindowHandle); - - if (windowInfo.IsMinimized) - { - windowInfo.Restore(); - Thread.Sleep(250); - } - - if (!windowInfo.IsActive) - { - windowInfo.Activate(); - Thread.Sleep(100); - } - - var metadata = new TaskMetadata(); - metadata.UpdateInfo(windowInfo); - - if (taskSettings.CaptureSettings.CaptureTransparent && !taskSettings.CaptureSettings.CaptureClientArea) - { - metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureWindowTransparent(WindowHandle); - } - else - { - metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureWindow(WindowHandle); - } - - return metadata; - } -} - diff --git a/SnapX.Core/DebugHelper.cs b/SnapX.Core/DebugHelper.cs index 7bdf634bf..6a6a1e222 100644 --- a/SnapX.Core/DebugHelper.cs +++ b/SnapX.Core/DebugHelper.cs @@ -2,8 +2,6 @@ using Serilog; -using Serilog.Events; -using Serilog.Sinks.InMemory; using Serilog.Sinks.SystemConsole.Themes; namespace SnapX.Core; @@ -12,8 +10,7 @@ public static class DebugHelper { public static ILogger? Logger { get; private set; } private static List messageBuffer = new(); - private static InMemorySink inMemorySink = new(); - public static IEnumerable LogEvents => inMemorySink.LogEvents; + public static ObservableSink observableSink { get; private set; } = new(); public static void Init(string logFilePath) { if (string.IsNullOrEmpty(logFilePath)) return; @@ -21,7 +18,7 @@ public static void Init(string logFilePath) #if DEBUG .MinimumLevel.Debug() #endif - .WriteTo.Sink(inMemorySink) + .WriteTo.Sink(observableSink) // If you run multiple SnapX instances, this will be the first to break. :) .WriteTo.Async(a => a.File(logFilePath, outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}]: {Message:lj}{NewLine}{Exception}", rollingInterval: RollingInterval.Day, buffered: true)); if (SnapX.LogToConsole) diff --git a/SnapX.Core/Enums.cs b/SnapX.Core/Enums.cs index e796758da..47cc8780b 100644 --- a/SnapX.Core/Enums.cs +++ b/SnapX.Core/Enums.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Events.cs b/SnapX.Core/Events.cs deleted file mode 100644 index a330154bb..000000000 --- a/SnapX.Core/Events.cs +++ /dev/null @@ -1,36 +0,0 @@ -using SnapX.Core.Job; -using Xdg.Directories; - -namespace SnapX.Core; - -public class NeedFileOpenerEvent -{ - public string Directory { get; set; } = UserDirectory.PicturesDir; - public string? FileName { get; set; } - public List? AcceptedExtensions { get; set; } - public string? Title { get; set; } = SnapX.AppName; - public bool Multiselect { get; set; } = false; - public TaskSettings TaskSettings { get; set; } -} - -public class NeedRegionCaptureEvent -{ - -} -public class EventAggregator -{ - private readonly List>> _subscriptions = []; - - public void Subscribe(Action action) - { - _subscriptions.Add(Tuple.Create>(typeof(TEvent), (o) => action((TEvent)o))); - } - - public void Publish(TEvent @event) - { - foreach (var subscription in _subscriptions.Where(s => s.Item1 == typeof(TEvent))) - { - subscription.Item2(@event); - } - } -} diff --git a/SnapX.Core/History/HistoryFilter.cs b/SnapX.Core/History/HistoryFilter.cs index af1440246..b9f5ea2f3 100644 --- a/SnapX.Core/History/HistoryFilter.cs +++ b/SnapX.Core/History/HistoryFilter.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -42,7 +41,7 @@ public IEnumerable ApplyFilter(IEnumerable historyItem string pattern = Regex.Escape(Filename).Replace("\\?", ".").Replace("\\*", ".*"); Regex regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); historyItems = historyItems.Where(x => (x.FileName != null && regex.IsMatch(x.FileName)) || - (SearchInTags && x.Tags != null && x.Tags.Any(tag => regex.IsMatch(tag.Text)))); + (SearchInTags && x.Tags != null && x.Tags.Any(tag => regex.IsMatch(tag.Name)))); } if (!string.IsNullOrEmpty(URL)) diff --git a/SnapX.Core/History/HistoryItem.cs b/SnapX.Core/History/HistoryItem.cs index 8e17d9da8..9a2c28391 100644 --- a/SnapX.Core/History/HistoryItem.cs +++ b/SnapX.Core/History/HistoryItem.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -15,7 +14,7 @@ namespace SnapX.Core.History; internal partial class HistoryContext : JsonSerializerContext; [Table("HistoryItems")] -public class HistoryItem +public record HistoryItem { [Key] public int Id { get; set; } @@ -33,14 +32,27 @@ public class HistoryItem public record Tag { public int Id { get; set; } - public string? Text { get; set; } - public string? WindowTitle { get; set; } - public string? ProcessName { get; set; } + public required string Name { get; set; } + public string Value { get; set; } = ""; + + public virtual bool Equals(Tag? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return Id == other.Id && + Name == other.Name && + Value == other.Value; + } + + public override int GetHashCode() + { + return HashCode.Combine(Id, Name, Value); + } } - public List? Tags { get; set; } = []; + public List? Tags = []; public override string ToString() { - string text = ""; + var text = ""; if (!string.IsNullOrEmpty(ShortenedURL)) { @@ -57,6 +69,7 @@ public override string ToString() return text; } + [JsonIgnore] public string TrayMenuText { get @@ -66,43 +79,49 @@ public string TrayMenuText return $"[{DateTime:HH:mm:ss}] {text}"; } } + [JsonIgnore] public string? BestImageSource => !string.IsNullOrWhiteSpace(FilePath) && File.Exists(FilePath) ? FilePath : URL ?? ThumbnailURL; - - public override bool Equals(object? obj) + public virtual bool Equals(HistoryItem? other) { - if (obj is not HistoryItem other) - { - return false; - } + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; - return Id == other.Id && - FileName == other.FileName && + return FileName == other.FileName && FilePath == other.FilePath && DateTime == other.DateTime && Type == other.Type && + Id == other.Id && Hidden == other.Hidden && Host == other.Host && URL == other.URL && ThumbnailURL == other.ThumbnailURL && DeletionURL == other.DeletionURL && ShortenedURL == other.ShortenedURL && - // Deep equality for Tags might be needed if you care about changes within the list - // This gets complex. Often, for lists, you might compare counts and then item-by-item, - // or just rely on a "LastModified" timestamp on the parent object. - (Tags?.SequenceEqual(other.Tags ?? Enumerable.Empty()) ?? (other.Tags == null)); + TagsEqual(Tags, other.Tags); + } + + private static bool TagsEqual(List? a, List? b) + { + if (a is null && b is null) return true; + if (a is null || b is null) return false; + if (a.Count != b.Count) return false; + + var orderedA = a.OrderBy(t => t.Id).ThenBy(t => t.Name).ThenBy(t => t.Value); + var orderedB = b.OrderBy(t => t.Id).ThenBy(t => t.Name).ThenBy(t => t.Value); + return orderedA.SequenceEqual(orderedB); } + public override int GetHashCode() { var hash = new HashCode(); - - hash.Add(Id); hash.Add(FileName); hash.Add(FilePath); hash.Add(DateTime); hash.Add(Type); + hash.Add(Id); hash.Add(Hidden); hash.Add(Host); hash.Add(URL); @@ -112,7 +131,7 @@ public override int GetHashCode() if (Tags != null) { - foreach (var tag in Tags) + foreach (var tag in Tags.OrderBy(t => t.Id).ThenBy(t => t.Name).ThenBy(t => t.Value)) { hash.Add(tag); } diff --git a/SnapX.Core/History/HistoryItemManager.cs b/SnapX.Core/History/HistoryItemManager.cs index 74e4c1476..d35e0eadc 100644 --- a/SnapX.Core/History/HistoryItemManager.cs +++ b/SnapX.Core/History/HistoryItemManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/History/HistoryManager.cs b/SnapX.Core/History/HistoryManager.cs index ca45207ec..300a683c8 100644 --- a/SnapX.Core/History/HistoryManager.cs +++ b/SnapX.Core/History/HistoryManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -62,6 +61,18 @@ public virtual bool RemoveHistoryItem(HistoryItem historyItem) return Save(FilePath, allHistoryItems); } + public virtual bool RemoveHistoryItems(HistoryItem[] historyItems) + { + var allHistoryItems = Load(); + foreach (var historyItem in historyItems) + { + var index = allHistoryItems.FindIndex(h => h.Id == historyItem.Id); + if (index == -1) + throw new InvalidOperationException($"History item with ID {historyItem.Id} was not found."); + allHistoryItems.RemoveAt(index); + } + return Save(FilePath, allHistoryItems); + } public virtual async Task> GetHistoryItemsAsync(int Items = int.MaxValue) diff --git a/SnapX.Core/History/HistoryManagerSQLite.cs b/SnapX.Core/History/HistoryManagerSQLite.cs index feb4ede7e..816021f0f 100644 --- a/SnapX.Core/History/HistoryManagerSQLite.cs +++ b/SnapX.Core/History/HistoryManagerSQLite.cs @@ -71,6 +71,30 @@ public override bool RemoveHistoryItem(HistoryItem historyItem) new { historyItem.Id }); return rowsAffected > 0; } + [DapperAot] + public override bool RemoveHistoryItems(HistoryItem[] items) + { + if (items.Length == 0) + return false; + + var allIds = items.Select(x => x.Id).ToArray(); + var deleted = 0; + + using var transaction = _connection.BeginTransaction(); + + for (var i = 0; i < allIds.Length; i += 999) + { + var batch = allIds.Skip(i).Take(999).ToArray(); + var parameters = batch.Select((id, index) => new { Name = $"@id{index}", Value = id }).ToList(); + var sql = $"DELETE FROM HistoryItems WHERE Id IN ({string.Join(", ", parameters.Select(p => p.Name))})"; + var paramDict = parameters.ToDictionary(p => p.Name, p => (object)p.Value); + deleted += _connection.Execute(sql, paramDict, transaction); + } + + transaction.Commit(); + + return deleted > 0; + } [DapperAot] public override HistoryItem UpdateHistoryItem(HistoryItem historyItem) @@ -159,9 +183,8 @@ INSERT INTO HistoryItems (h, t) => new { HistoryItemId = h.Id, - t.Text, - t.WindowTitle, - t.ProcessName + t.Name, + t.Value, }); if (allTags.Any()) diff --git a/SnapX.Core/History/HistorySettings.cs b/SnapX.Core/History/HistorySettings.cs index d1a3e6e7a..bfec22095 100644 --- a/SnapX.Core/History/HistorySettings.cs +++ b/SnapX.Core/History/HistorySettings.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.History; -public class HistorySettings +public record HistorySettings { public bool RememberWindowState { get; set; } = true; public int SplitterDistance { get; set; } = 550; diff --git a/SnapX.Core/History/ImageHistorySettings.cs b/SnapX.Core/History/ImageHistorySettings.cs new file mode 100644 index 000000000..7cfe58a07 --- /dev/null +++ b/SnapX.Core/History/ImageHistorySettings.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp; + +namespace SnapX.Core.History; + + +public class WindowState +{ + public Point Location { get; set; } + public Size Size { get; set; } + public bool IsMaximized { get; set; } +} +public class ImageHistorySettings +{ + public bool RememberWindowState { get; set; } = true; + public WindowState WindowState { get; set; } = new(); + public Size ThumbnailSize { get; set; } = new(150, 150); + public int MaxItemCount { get; set; } = 250; + public bool FilterMissingFiles { get; set; } = false; + public bool RememberSearchText { get; set; } = false; + public string SearchText { get; set; } = ""; +} diff --git a/SnapX.Core/Hotkey/HotkeyInfo.cs b/SnapX.Core/Hotkey/HotkeyInfo.cs index 592c1f0d0..7f10557bb 100644 --- a/SnapX.Core/Hotkey/HotkeyInfo.cs +++ b/SnapX.Core/Hotkey/HotkeyInfo.cs @@ -3,7 +3,7 @@ namespace SnapX.Core.Hotkey; -public class HotkeyInfo +public record HotkeyInfo() { public Keys Hotkey { get; set; } @@ -11,7 +11,7 @@ public class HotkeyInfo public ushort ID { get; set; } [JsonIgnore] - public HotkeyStatus Status { get; set; } + public HotkeyStatus Status { get; set; } = HotkeyStatus.NotConfigured; public Keys KeyCode => Hotkey & Keys.KeyCode; @@ -29,7 +29,7 @@ public Modifiers ModifiersEnum { get { - Modifiers modifiers = Modifiers.None; + var modifiers = Modifiers.None; if (Alt) modifiers |= Modifiers.Alt; if (Control) modifiers |= Modifiers.Control; @@ -44,11 +44,6 @@ public Modifiers ModifiersEnum public bool IsValidHotkey => KeyCode != Keys.None && !IsOnlyModifiers; - public HotkeyInfo() - { - Status = HotkeyStatus.NotConfigured; - } - public HotkeyInfo(Keys hotkey) : this() { Hotkey = hotkey; @@ -61,7 +56,7 @@ public HotkeyInfo(Keys hotkey, ushort id) : this(hotkey) public override string ToString() { - string text = ""; + var text = ""; if (Control) { @@ -107,13 +102,13 @@ public override string ToString() { text += "Scroll Lock"; } - else if (KeyCode >= Keys.D0 && KeyCode <= Keys.D9) + else if (KeyCode is >= Keys.D0 and <= Keys.D9) { text += (KeyCode - Keys.D0).ToString(); } - else if (KeyCode >= Keys.NumPad0 && KeyCode <= Keys.NumPad9) + else if (KeyCode is >= Keys.NumPad0 and <= Keys.NumPad9) { - text += "Numpad " + (KeyCode - Keys.NumPad0).ToString(); + text += "Numpad " + (KeyCode - Keys.NumPad0); } else { @@ -125,11 +120,11 @@ public override string ToString() private string ToStringWithSpaces(Keys key) { - string name = key.ToString(); + var name = key.ToString(); var result = new StringBuilder(); - for (int i = 0; i < name.Length; i++) + for (var i = 0; i < name.Length; i++) { if (i > 0 && char.IsUpper(name[i])) { diff --git a/SnapX.Core/Hotkey/HotkeyManager.cs b/SnapX.Core/Hotkey/HotkeyManager.cs index 0826ed7b8..9780ec539 100644 --- a/SnapX.Core/Hotkey/HotkeyManager.cs +++ b/SnapX.Core/Hotkey/HotkeyManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Hotkey/HotkeySettings.cs b/SnapX.Core/Hotkey/HotkeySettings.cs index f34c189ba..2a88926e4 100644 --- a/SnapX.Core/Hotkey/HotkeySettings.cs +++ b/SnapX.Core/Hotkey/HotkeySettings.cs @@ -1,20 +1,14 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SnapX.Core.Job; namespace SnapX.Core.Hotkey; -public class HotkeySettings +public record HotkeySettings() { - public HotkeyInfo HotkeyInfo { get; set; } - - public TaskSettings TaskSettings { get; set; } + public HotkeyInfo? HotkeyInfo { get; set; } = new(); - public HotkeySettings() - { - HotkeyInfo = new HotkeyInfo(); - } + public TaskSettings? TaskSettings { get; set; } public HotkeySettings(HotkeyType job, Keys hotkey = Keys.None) : this() { @@ -27,7 +21,7 @@ public override string ToString() { if (HotkeyInfo != null && TaskSettings != null) { - return string.Format("Hotkey: {0}, Description: {1}, Job: {2}", HotkeyInfo, TaskSettings, TaskSettings.Job); + return $"Hotkey: {HotkeyInfo}, Description: {TaskSettings}, Job: {TaskSettings.Job}"; } return ""; diff --git a/SnapX.Core/Hotkey/HotkeysConfig.cs b/SnapX.Core/Hotkey/HotkeysConfig.cs index 72edba478..8baf56e7f 100644 --- a/SnapX.Core/Hotkey/HotkeysConfig.cs +++ b/SnapX.Core/Hotkey/HotkeysConfig.cs @@ -2,7 +2,7 @@ namespace SnapX.Core.Hotkey; -public class HotkeysConfig +public record HotkeysConfig { public List Hotkeys = HotkeyManager.GetDefaultHotkeyList(); } diff --git a/SnapX.Core/Hotkey/Keys.cs b/SnapX.Core/Hotkey/Keys.cs index 18bbe0252..b027c12c9 100644 --- a/SnapX.Core/Hotkey/Keys.cs +++ b/SnapX.Core/Hotkey/Keys.cs @@ -1,5 +1,5 @@ namespace SnapX.Core.Hotkey; - +[Flags] public enum Keys { None = 0, @@ -158,6 +158,7 @@ public enum Keys } +[Flags] public enum Modifiers { None = 0, diff --git a/SnapX.Core/ImageEffects/Adjustments/Alpha.cs b/SnapX.Core/ImageEffects/Adjustments/Alpha.cs index 55698c753..c77943e85 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Alpha.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Alpha.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/BlackWhite.cs b/SnapX.Core/ImageEffects/Adjustments/BlackWhite.cs index 409dea6f9..e17ccd86d 100644 --- a/SnapX.Core/ImageEffects/Adjustments/BlackWhite.cs +++ b/SnapX.Core/ImageEffects/Adjustments/BlackWhite.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Brightness.cs b/SnapX.Core/ImageEffects/Adjustments/Brightness.cs index cdcee5f62..c9ae78d88 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Brightness.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Brightness.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Colorize.cs b/SnapX.Core/ImageEffects/Adjustments/Colorize.cs index 1d3fac252..f4d82558d 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Colorize.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Colorize.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Contrast.cs b/SnapX.Core/ImageEffects/Adjustments/Contrast.cs index 82ef6164a..d7b19ba90 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Contrast.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Contrast.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Gamma.cs b/SnapX.Core/ImageEffects/Adjustments/Gamma.cs index 82920e931..c72f97cd6 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Gamma.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Gamma.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Grayscale.cs b/SnapX.Core/ImageEffects/Adjustments/Grayscale.cs index 650dab33e..041659e0f 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Grayscale.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Grayscale.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Hue.cs b/SnapX.Core/ImageEffects/Adjustments/Hue.cs index dddb5d6a0..8a110ab2f 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Hue.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Hue.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/MatrixColor.cs b/SnapX.Core/ImageEffects/Adjustments/MatrixColor.cs index 7a6c50911..177bff51f 100644 --- a/SnapX.Core/ImageEffects/Adjustments/MatrixColor.cs +++ b/SnapX.Core/ImageEffects/Adjustments/MatrixColor.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/ReplaceColor.cs b/SnapX.Core/ImageEffects/Adjustments/ReplaceColor.cs index 568aa47c2..a034b8b09 100644 --- a/SnapX.Core/ImageEffects/Adjustments/ReplaceColor.cs +++ b/SnapX.Core/ImageEffects/Adjustments/ReplaceColor.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Saturation.cs b/SnapX.Core/ImageEffects/Adjustments/Saturation.cs index 727a48604..a62dff0f9 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Saturation.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Saturation.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/SelectiveColor.cs b/SnapX.Core/ImageEffects/Adjustments/SelectiveColor.cs index 01c398cfc..274b4f423 100644 --- a/SnapX.Core/ImageEffects/Adjustments/SelectiveColor.cs +++ b/SnapX.Core/ImageEffects/Adjustments/SelectiveColor.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Adjustments/Sepia.cs b/SnapX.Core/ImageEffects/Adjustments/Sepia.cs index 0a347fd2d..ccf01e698 100644 --- a/SnapX.Core/ImageEffects/Adjustments/Sepia.cs +++ b/SnapX.Core/ImageEffects/Adjustments/Sepia.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawBackground.cs b/SnapX.Core/ImageEffects/Drawings/DrawBackground.cs index f1fbf980a..4740afff4 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawBackground.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawBackground.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawBackgroundImage.cs b/SnapX.Core/ImageEffects/Drawings/DrawBackgroundImage.cs index db82694f6..3bad927a9 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawBackgroundImage.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawBackgroundImage.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawBorder.cs b/SnapX.Core/ImageEffects/Drawings/DrawBorder.cs index 88eef2fa7..887c880c6 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawBorder.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawBorder.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawCheckerboard.cs b/SnapX.Core/ImageEffects/Drawings/DrawCheckerboard.cs index f6e6681af..6c7ed65ce 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawCheckerboard.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawCheckerboard.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawImage.cs b/SnapX.Core/ImageEffects/Drawings/DrawImage.cs index 87db843cc..29d9a67ff 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawImage.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawImage.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawParticles.cs b/SnapX.Core/ImageEffects/Drawings/DrawParticles.cs index 7fc391bc0..7187140e7 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawParticles.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawParticles.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawText.cs b/SnapX.Core/ImageEffects/Drawings/DrawText.cs index 5d9e56e5c..e14038102 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawText.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawText.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Drawings/DrawTextEx.cs b/SnapX.Core/ImageEffects/Drawings/DrawTextEx.cs index b0acd2b4f..460b9a94e 100644 --- a/SnapX.Core/ImageEffects/Drawings/DrawTextEx.cs +++ b/SnapX.Core/ImageEffects/Drawings/DrawTextEx.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Enums.cs b/SnapX.Core/ImageEffects/Enums.cs index 758e38883..6dc5595e7 100644 --- a/SnapX.Core/ImageEffects/Enums.cs +++ b/SnapX.Core/ImageEffects/Enums.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Blur.cs b/SnapX.Core/ImageEffects/Filters/Blur.cs index 95488c96a..c87aecf1d 100644 --- a/SnapX.Core/ImageEffects/Filters/Blur.cs +++ b/SnapX.Core/ImageEffects/Filters/Blur.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/EdgeDetect.cs b/SnapX.Core/ImageEffects/Filters/EdgeDetect.cs index 1cc2652eb..803f08a78 100644 --- a/SnapX.Core/ImageEffects/Filters/EdgeDetect.cs +++ b/SnapX.Core/ImageEffects/Filters/EdgeDetect.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Emboss.cs b/SnapX.Core/ImageEffects/Filters/Emboss.cs index 58b66c69c..b1b17cb1a 100644 --- a/SnapX.Core/ImageEffects/Filters/Emboss.cs +++ b/SnapX.Core/ImageEffects/Filters/Emboss.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Numerics; diff --git a/SnapX.Core/ImageEffects/Filters/GaussianBlur.cs b/SnapX.Core/ImageEffects/Filters/GaussianBlur.cs index a82b31934..19a008c97 100644 --- a/SnapX.Core/ImageEffects/Filters/GaussianBlur.cs +++ b/SnapX.Core/ImageEffects/Filters/GaussianBlur.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.ComponentModel; diff --git a/SnapX.Core/ImageEffects/Filters/Glow.cs b/SnapX.Core/ImageEffects/Filters/Glow.cs index 2887b8cd5..f15eeba63 100644 --- a/SnapX.Core/ImageEffects/Filters/Glow.cs +++ b/SnapX.Core/ImageEffects/Filters/Glow.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/MatrixConvolution.cs b/SnapX.Core/ImageEffects/Filters/MatrixConvolution.cs index fb3864983..0fdafce45 100644 --- a/SnapX.Core/ImageEffects/Filters/MatrixConvolution.cs +++ b/SnapX.Core/ImageEffects/Filters/MatrixConvolution.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/MeanRemoval.cs b/SnapX.Core/ImageEffects/Filters/MeanRemoval.cs index 20170729b..74d8291a0 100644 --- a/SnapX.Core/ImageEffects/Filters/MeanRemoval.cs +++ b/SnapX.Core/ImageEffects/Filters/MeanRemoval.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Outline.cs b/SnapX.Core/ImageEffects/Filters/Outline.cs index d65ae6b63..865ee9a00 100644 --- a/SnapX.Core/ImageEffects/Filters/Outline.cs +++ b/SnapX.Core/ImageEffects/Filters/Outline.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Pixelate.cs b/SnapX.Core/ImageEffects/Filters/Pixelate.cs index 0bf7280dd..c0f10578a 100644 --- a/SnapX.Core/ImageEffects/Filters/Pixelate.cs +++ b/SnapX.Core/ImageEffects/Filters/Pixelate.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/RGBSplit.cs b/SnapX.Core/ImageEffects/Filters/RGBSplit.cs index 3bbf133d4..5be9366ab 100644 --- a/SnapX.Core/ImageEffects/Filters/RGBSplit.cs +++ b/SnapX.Core/ImageEffects/Filters/RGBSplit.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Reflection.cs b/SnapX.Core/ImageEffects/Filters/Reflection.cs index 32a833a01..bfb9fb3a8 100644 --- a/SnapX.Core/ImageEffects/Filters/Reflection.cs +++ b/SnapX.Core/ImageEffects/Filters/Reflection.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Shadow.cs b/SnapX.Core/ImageEffects/Filters/Shadow.cs index e376c25d9..da3690395 100644 --- a/SnapX.Core/ImageEffects/Filters/Shadow.cs +++ b/SnapX.Core/ImageEffects/Filters/Shadow.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/Slice.cs b/SnapX.Core/ImageEffects/Filters/Slice.cs index 552c540e3..26ec405a7 100644 --- a/SnapX.Core/ImageEffects/Filters/Slice.cs +++ b/SnapX.Core/ImageEffects/Filters/Slice.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/TornEdge.cs b/SnapX.Core/ImageEffects/Filters/TornEdge.cs index e129205ef..e6470b9e2 100644 --- a/SnapX.Core/ImageEffects/Filters/TornEdge.cs +++ b/SnapX.Core/ImageEffects/Filters/TornEdge.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Filters/WaveEdge.cs b/SnapX.Core/ImageEffects/Filters/WaveEdge.cs index c940e1b00..6336e604c 100644 --- a/SnapX.Core/ImageEffects/Filters/WaveEdge.cs +++ b/SnapX.Core/ImageEffects/Filters/WaveEdge.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/ImageEffect.cs b/SnapX.Core/ImageEffects/ImageEffect.cs index ae833b876..07c733244 100644 --- a/SnapX.Core/ImageEffects/ImageEffect.cs +++ b/SnapX.Core/ImageEffects/ImageEffect.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/ImageEffectPackager.cs b/SnapX.Core/ImageEffects/ImageEffectPackager.cs index 7a69aeac5..67b9a256a 100644 --- a/SnapX.Core/ImageEffects/ImageEffectPackager.cs +++ b/SnapX.Core/ImageEffects/ImageEffectPackager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/ImageEffectPreset.cs b/SnapX.Core/ImageEffects/ImageEffectPreset.cs index 1e2e7028e..62bae19d0 100644 --- a/SnapX.Core/ImageEffects/ImageEffectPreset.cs +++ b/SnapX.Core/ImageEffects/ImageEffectPreset.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/AutoCrop.cs b/SnapX.Core/ImageEffects/Manipulations/AutoCrop.cs index 1b4e3e1eb..bdb5c8712 100644 --- a/SnapX.Core/ImageEffects/Manipulations/AutoCrop.cs +++ b/SnapX.Core/ImageEffects/Manipulations/AutoCrop.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Canvas.cs b/SnapX.Core/ImageEffects/Manipulations/Canvas.cs index be0102ef6..259e2db05 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Canvas.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Canvas.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Crop.cs b/SnapX.Core/ImageEffects/Manipulations/Crop.cs index becc2a8db..47beb3c51 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Crop.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Crop.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Flip.cs b/SnapX.Core/ImageEffects/Manipulations/Flip.cs index 36e8e718d..43b51050e 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Flip.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Flip.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/ForceProportions.cs b/SnapX.Core/ImageEffects/Manipulations/ForceProportions.cs index 44094f211..0059b2b12 100644 --- a/SnapX.Core/ImageEffects/Manipulations/ForceProportions.cs +++ b/SnapX.Core/ImageEffects/Manipulations/ForceProportions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Resize.cs b/SnapX.Core/ImageEffects/Manipulations/Resize.cs index 804cf00ce..9cd4ab7e3 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Resize.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Resize.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Rotate.cs b/SnapX.Core/ImageEffects/Manipulations/Rotate.cs index b5c66df1d..07da43dae 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Rotate.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Rotate.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/RoundedCorners.cs b/SnapX.Core/ImageEffects/Manipulations/RoundedCorners.cs index 6f79c32f0..71fabcb97 100644 --- a/SnapX.Core/ImageEffects/Manipulations/RoundedCorners.cs +++ b/SnapX.Core/ImageEffects/Manipulations/RoundedCorners.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Scale.cs b/SnapX.Core/ImageEffects/Manipulations/Scale.cs index e5136c876..72e642e5d 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Scale.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Scale.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/Manipulations/Skew.cs b/SnapX.Core/ImageEffects/Manipulations/Skew.cs index 20e385e48..3eec948e3 100644 --- a/SnapX.Core/ImageEffects/Manipulations/Skew.cs +++ b/SnapX.Core/ImageEffects/Manipulations/Skew.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/ImageEffects/WatermarkConfig.cs b/SnapX.Core/ImageEffects/WatermarkConfig.cs index 9064f9914..8d1f6e861 100644 --- a/SnapX.Core/ImageEffects/WatermarkConfig.cs +++ b/SnapX.Core/ImageEffects/WatermarkConfig.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Indexer/Enums.cs b/SnapX.Core/Indexer/Enums.cs index b4223d0d1..1cb3d89eb 100644 --- a/SnapX.Core/Indexer/Enums.cs +++ b/SnapX.Core/Indexer/Enums.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Indexer/FolderInfo.cs b/SnapX.Core/Indexer/FolderInfo.cs index 7108b6e32..6f2ab5153 100644 --- a/SnapX.Core/Indexer/FolderInfo.cs +++ b/SnapX.Core/Indexer/FolderInfo.cs @@ -1,34 +1,28 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using static System.String; + namespace SnapX.Core.Indexer; -public class FolderInfo +public record FolderInfo(string FolderPath) { - public string FolderPath { get; set; } - public List Files { get; set; } - public List Folders { get; set; } + public string FolderPath { get; set; } = FolderPath; + public List Files { get; set; } = []; + public List Folders { get; set; } = []; public long Size { get; private set; } public int TotalFileCount { get; private set; } public int TotalFolderCount { get; private set; } - public FolderInfo Parent { get; set; } + public FolderInfo? Parent { get; set; } public string FolderName => Path.GetFileName(FolderPath); public bool IsEmpty => TotalFileCount == 0 && TotalFolderCount == 0; - public FolderInfo(string folderPath) - { - FolderPath = folderPath; - Files = []; - Folders = []; - } - public void Update() { Folders.ForEach(x => x.Update()); - Folders.Sort((x, y) => x.FolderName.CompareTo(y.FolderName)); + Folders.Sort((x, y) => Compare(x.FolderName, y.FolderName, StringComparison.Ordinal)); Size = Folders.Sum(x => x.Size) + Files.Sum(x => x.Length); TotalFileCount = Files.Count + Folders.Sum(x => x.TotalFileCount); TotalFolderCount = Folders.Count + Folders.Sum(x => x.TotalFolderCount); diff --git a/SnapX.Core/Indexer/HtmlHelper.cs b/SnapX.Core/Indexer/HtmlHelper.cs index 20bcddf10..5d53acc34 100644 --- a/SnapX.Core/Indexer/HtmlHelper.cs +++ b/SnapX.Core/Indexer/HtmlHelper.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -10,14 +9,14 @@ public static class HtmlHelper { public static string StartTag(string tag, string style = "", string otherFields = "") { - string css = ""; + var css = ""; if (!string.IsNullOrEmpty(style)) { css = $" style=\"{style}\""; } - string fields = ""; + var fields = ""; if (!string.IsNullOrEmpty(otherFields)) { diff --git a/SnapX.Core/Indexer/Indexer.cs b/SnapX.Core/Indexer/Indexer.cs index b6cdd5aba..56a287f61 100644 --- a/SnapX.Core/Indexer/Indexer.cs +++ b/SnapX.Core/Indexer/Indexer.cs @@ -1,16 +1,14 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using static System.String; + namespace SnapX.Core.Indexer; -public abstract class Indexer +public abstract class Indexer(IndexerSettings IndexerSettings) { - protected IndexerSettings settings = null; - protected Indexer(IndexerSettings indexerSettings) - { - settings = indexerSettings; - } + protected IndexerSettings? settings = IndexerSettings; + public string? Index(string? folderPath) { Indexer indexer = null; @@ -60,27 +58,27 @@ protected Indexer(IndexerSettings indexerSettings) protected FolderInfo GetFolderInfo(string folderPath, int level = 0) { - FolderInfo folderInfo = new FolderInfo(folderPath); + var folderInfo = new FolderInfo(folderPath); if (settings.MaxDepthLevel == 0 || level < settings.MaxDepthLevel) { try { - DirectoryInfo currentDirectoryInfo = new DirectoryInfo(folderPath); + var currentDirectoryInfo = new DirectoryInfo(folderPath); - foreach (DirectoryInfo directoryInfo in currentDirectoryInfo.EnumerateDirectories()) + foreach (var directoryInfo in currentDirectoryInfo.EnumerateDirectories()) { if (settings.SkipHiddenFolders && directoryInfo.Attributes.HasFlag(FileAttributes.Hidden)) { continue; } - FolderInfo subFolderInfo = GetFolderInfo(directoryInfo.FullName, level + 1); + var subFolderInfo = GetFolderInfo(directoryInfo.FullName, level + 1); folderInfo.Folders.Add(subFolderInfo); subFolderInfo.Parent = folderInfo; } - foreach (FileInfo fileInfo in currentDirectoryInfo.EnumerateFiles()) + foreach (var fileInfo in currentDirectoryInfo.EnumerateFiles()) { if (settings.SkipHiddenFiles && fileInfo.Attributes.HasFlag(FileAttributes.Hidden)) { @@ -90,7 +88,7 @@ protected FolderInfo GetFolderInfo(string folderPath, int level = 0) folderInfo.Files.Add(fileInfo); } - folderInfo.Files.Sort((x, y) => x.Name.CompareTo(y.Name)); + folderInfo.Files.Sort((x, y) => Compare(x.Name, y.Name, StringComparison.Ordinal)); } catch (UnauthorizedAccessException) { diff --git a/SnapX.Core/Indexer/IndexerHtml.cs b/SnapX.Core/Indexer/IndexerHtml.cs index 977a1532b..ef20c5475 100644 --- a/SnapX.Core/Indexer/IndexerHtml.cs +++ b/SnapX.Core/Indexer/IndexerHtml.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Indexer/IndexerJson.cs b/SnapX.Core/Indexer/IndexerJson.cs index b2be409a5..9272a4488 100644 --- a/SnapX.Core/Indexer/IndexerJson.cs +++ b/SnapX.Core/Indexer/IndexerJson.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Indexer/IndexerText.cs b/SnapX.Core/Indexer/IndexerText.cs index 8a0f830fc..6369aa25c 100644 --- a/SnapX.Core/Indexer/IndexerText.cs +++ b/SnapX.Core/Indexer/IndexerText.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Indexer/IndexerXml.cs b/SnapX.Core/Indexer/IndexerXml.cs index 0b4e1258d..69c241cb4 100644 --- a/SnapX.Core/Indexer/IndexerXml.cs +++ b/SnapX.Core/Indexer/IndexerXml.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -15,26 +14,24 @@ public IndexerXml(IndexerSettings indexerSettings) : base(indexerSettings) public string Index(string folderPath) { - FolderInfo folderInfo = new FolderInfo(folderPath); + var folderInfo = new FolderInfo(folderPath); folderInfo.Update(); - XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); + var xmlWriterSettings = new XmlWriterSettings(); xmlWriterSettings.Encoding = new UTF8Encoding(false); xmlWriterSettings.ConformanceLevel = ConformanceLevel.Document; xmlWriterSettings.Indent = true; - using (MemoryStream ms = new MemoryStream()) + using var ms = new MemoryStream(); + using (xmlWriter = XmlWriter.Create(ms, xmlWriterSettings)) { - using (xmlWriter = XmlWriter.Create(ms, xmlWriterSettings)) - { - xmlWriter.WriteStartDocument(); - IndexFolder(folderInfo); - xmlWriter.WriteEndDocument(); - xmlWriter.Flush(); - } - - return Encoding.UTF8.GetString(ms.ToArray()); + xmlWriter.WriteStartDocument(); + IndexFolder(folderInfo); + xmlWriter.WriteEndDocument(); + xmlWriter.Flush(); } + + return Encoding.UTF8.GetString(ms.ToArray()); } protected override void IndexFolder(FolderInfo dir, int level = 0) @@ -45,7 +42,7 @@ protected override void IndexFolder(FolderInfo dir, int level = 0) { xmlWriter.WriteStartElement("Files"); - foreach (FileInfo fi in dir.Files) + foreach (var _ in dir.Files) { xmlWriter.WriteStartElement("File"); @@ -59,9 +56,9 @@ protected override void IndexFolder(FolderInfo dir, int level = 0) { xmlWriter.WriteStartElement("Folders"); - foreach (FolderInfo subdir in dir.Folders) + foreach (var subDir in dir.Folders) { - IndexFolder(subdir); + IndexFolder(subDir); } xmlWriter.WriteEndElement(); diff --git a/SnapX.Core/Interfaces/IDelayService.cs b/SnapX.Core/Interfaces/IDelayService.cs new file mode 100644 index 000000000..722a1738e --- /dev/null +++ b/SnapX.Core/Interfaces/IDelayService.cs @@ -0,0 +1,6 @@ +namespace SnapX.Core.Interfaces; + +public interface IDelayService +{ + Task DelayAsync(int milliseconds); +} diff --git a/SnapX.Core/Interfaces/IFilePicker.cs b/SnapX.Core/Interfaces/IFilePicker.cs new file mode 100644 index 000000000..0b642c349 --- /dev/null +++ b/SnapX.Core/Interfaces/IFilePicker.cs @@ -0,0 +1,13 @@ +namespace SnapX.Core.Interfaces; + +public interface IFilePicker +{ + /// + /// Prompts the user to select one or more files. + /// + /// Dialog title. + /// Optional initial directory. + /// Allow selecting multiple files. + /// Array of selected file paths, or empty array if cancelled. + Task PickFilesAsync(string title, string initialDirectory, bool allowMultiple); +} diff --git a/SnapX.Core/Interfaces/ILoggerService.cs b/SnapX.Core/Interfaces/ILoggerService.cs new file mode 100644 index 000000000..875cc83de --- /dev/null +++ b/SnapX.Core/Interfaces/ILoggerService.cs @@ -0,0 +1,20 @@ +using Serilog.Core; + +namespace SnapX.Core.Interfaces; + +public interface ILoggerService +{ + ILogScope BeginScope(string name); + [MessageTemplateFormatMethod("messageTemplate")] + void Debug(string messageTemplate, params object[] propertyValues); + [MessageTemplateFormatMethod("messageTemplate")] + void Information(string messageTemplate, params object[] propertyValues); + [MessageTemplateFormatMethod("messageTemplate")] + void Warning(string messageTemplate, params object[] propertyValues); + [MessageTemplateFormatMethod("messageTemplate")] + void Error(string messageTemplate, params object[] propertyValues); + [MessageTemplateFormatMethod("messageTemplate")] + void Error(Exception exception, string messageTemplate, params object[] propertyValues); +} + +public interface ILogScope : IDisposable; diff --git a/SnapX.Core/Interfaces/IMainWindowService.cs b/SnapX.Core/Interfaces/IMainWindowService.cs new file mode 100644 index 000000000..cf1231ae5 --- /dev/null +++ b/SnapX.Core/Interfaces/IMainWindowService.cs @@ -0,0 +1,7 @@ +namespace SnapX.Core.SharpCapture.Interfaces; + +public interface IMainWindowService +{ + Task HideAsync(); + Task ForceActivateAsync(); +} diff --git a/SnapX.Core/Interfaces/INotificationService.cs b/SnapX.Core/Interfaces/INotificationService.cs new file mode 100644 index 000000000..54873aebc --- /dev/null +++ b/SnapX.Core/Interfaces/INotificationService.cs @@ -0,0 +1,9 @@ +using SnapX.Core.Job; + +namespace SnapX.Core.Interfaces; + +public interface INotificationService +{ + Task CloseActiveFormAsync(); + Task PlayNotificationSoundAsync(NotificationSound sound, TaskSettings settings); +} diff --git a/SnapX.Core/Interfaces/IUploadManager.cs b/SnapX.Core/Interfaces/IUploadManager.cs new file mode 100644 index 000000000..a15df2c1d --- /dev/null +++ b/SnapX.Core/Interfaces/IUploadManager.cs @@ -0,0 +1,8 @@ +using SnapX.Core.Job; + +namespace SnapX.Core.Interfaces; + +public interface IUploadManager +{ + Task RunImageTaskAsync(TaskMetadata metadata, TaskSettings taskSettings); +} diff --git a/SnapX.Core/Job/QuickTaskInfo.cs b/SnapX.Core/Job/QuickTaskInfo.cs index c57601a16..bd61edcb3 100644 --- a/SnapX.Core/Job/QuickTaskInfo.cs +++ b/SnapX.Core/Job/QuickTaskInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Job/TaskEx.cs b/SnapX.Core/Job/TaskEx.cs index 18eea9f7b..12a486a19 100644 --- a/SnapX.Core/Job/TaskEx.cs +++ b/SnapX.Core/Job/TaskEx.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Job/TaskHelpers.cs b/SnapX.Core/Job/TaskHelpers.cs index ce0051772..b8161f3a7 100644 --- a/SnapX.Core/Job/TaskHelpers.cs +++ b/SnapX.Core/Job/TaskHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -22,11 +21,10 @@ using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SnapX.Core.Capture; using SnapX.Core.CLI; using SnapX.Core.ImageEffects; using SnapX.Core.Media; -using SnapX.Core.ScreenCapture; +using SnapX.Core.SharpCapture; using SnapX.Core.Upload; using SnapX.Core.Upload.Custom; using SnapX.Core.Upload.SharingServices; @@ -47,12 +45,12 @@ public static async Task ExecuteJob(HotkeyType job, CLICommand command = null) await ExecuteJob(SnapX.DefaultTaskSettings, job, command); } - public static async Task ExecuteJob(TaskSettings taskSettings) + public static async Task ExecuteJob(TaskSettings? taskSettings) { await ExecuteJob(taskSettings, taskSettings.Job); } - public static async Task ExecuteJob(TaskSettings taskSettings, HotkeyType job, CLICommand command = null) + public static async Task ExecuteJob(TaskSettings? taskSettings, HotkeyType job, CLICommand command = null) { if (job == HotkeyType.None) return; @@ -100,31 +98,31 @@ public static async Task ExecuteJob(TaskSettings taskSettings, HotkeyType job, C break; // Screen capture case HotkeyType.PrintScreen: - new CaptureFullscreen().Capture(safeTaskSettings); + // new CaptureFullscreen().CaptureAsync(safeTaskSettings); break; case HotkeyType.ActiveWindow: - new CaptureActiveWindow().Capture(safeTaskSettings); + // new CaptureActiveWindow().CaptureAsync(safeTaskSettings); break; case HotkeyType.ActiveMonitor: - new CaptureActiveMonitor().Capture(safeTaskSettings); + // new CaptureActiveMonitor().CaptureAsync(safeTaskSettings); break; case HotkeyType.RectangleRegion: - new CaptureRegion().Capture(safeTaskSettings); + // new CaptureRegion().CaptureAsync(safeTaskSettings); break; case HotkeyType.RectangleLight: - new CaptureRegion(RegionCaptureType.Light).Capture(safeTaskSettings); + // new CaptureRegion(RegionCaptureType.Light).Capture(safeTaskSettings); break; case HotkeyType.RectangleTransparent: - new CaptureRegion(RegionCaptureType.Transparent).Capture(safeTaskSettings); + // new CaptureRegion(RegionCaptureType.Transparent).Capture(safeTaskSettings); break; case HotkeyType.CustomRegion: - new CaptureCustomRegion().Capture(safeTaskSettings); + // new CaptureCustomRegion().Capture(safeTaskSettings); break; case HotkeyType.CustomWindow: - new CaptureCustomWindow().Capture(safeTaskSettings); + // new CaptureCustomWindow().Capture(safeTaskSettings); break; case HotkeyType.LastRegion: - new CaptureLastRegion().Capture(safeTaskSettings); + // new CaptureLastRegion().Capture(safeTaskSettings); break; case HotkeyType.ScrollingCapture: DebugHelper.WriteException("HotkeyType.ScrollingCapture is NOT implemented."); @@ -321,7 +319,7 @@ public static async Task ExecuteJob(TaskSettings taskSettings, HotkeyType job, C } } - public static ImageData PrepareImage(Image img, TaskSettings taskSettings) + public static ImageData PrepareImage(Image img, TaskSettings? taskSettings) { var imageData = new ImageData(); imageData.ImageStream = SaveImageAsStream(img, taskSettings.ImageSettings.ImageFormat, taskSettings); @@ -371,7 +369,7 @@ public static ImageData PrepareImage(Image img, TaskSettings taskSettings) // return null; // } - public static MemoryStream SaveImageAsStream(Image img, EImageFormat imageFormat, TaskSettings taskSettings) + public static MemoryStream SaveImageAsStream(Image img, EImageFormat imageFormat, TaskSettings? taskSettings) { return SaveImageAsStream(img, imageFormat, taskSettings.ImageSettings.ImagePNGBitDepth, taskSettings.ImageSettings.ImageJPEGQuality, taskSettings.ImageSettings.ImageGIFQuality); @@ -417,7 +415,7 @@ public static MemoryStream SaveImageAsStream(Image image, EImageFormat imageForm return ms; } - public static void SaveImageAsFile(Image img, TaskSettings taskSettings, bool overwriteFile = false) + public static void SaveImageAsFile(Image img, TaskSettings? taskSettings, bool overwriteFile = false) { using (ImageData imageData = PrepareImage(img, taskSettings)) { @@ -437,7 +435,7 @@ public static void SaveImageAsFile(Image img, TaskSettings taskSettings, bool ov } } } - public static string? HandleExistsFile(string? filePath, TaskSettings taskSettings) + public static string? HandleExistsFile(string? filePath, TaskSettings? taskSettings) { if (File.Exists(filePath)) { @@ -457,18 +455,18 @@ public static void SaveImageAsFile(Image img, TaskSettings taskSettings, bool ov return filePath; } - public static string? HandleExistsFile(string? folderPath, string? fileName, TaskSettings taskSettings) + public static string? HandleExistsFile(string? folderPath, string? fileName, TaskSettings? taskSettings) { var filePath = Path.Combine(folderPath, fileName); return HandleExistsFile(filePath, taskSettings); } - public static string? GetFileName(TaskSettings taskSettings, string extension, Image bmp) + public static string? GetFileName(TaskSettings? taskSettings, string extension, Image bmp) { var metadata = new TaskMetadata(bmp); return GetFileName(taskSettings, extension, metadata); } - public static string? GetFileName(TaskSettings taskSettings, string extension = null, TaskMetadata metadata = null) + public static string? GetFileName(TaskSettings? taskSettings, string extension = null, TaskMetadata metadata = null) { string? fileName; @@ -511,7 +509,7 @@ public static void SaveImageAsFile(Image img, TaskSettings taskSettings, bool ov return fileName; } - public static string? GetScreenshotsFolder(TaskSettings taskSettings = null, TaskMetadata metadata = null, DateTime? date = null) + public static string? GetScreenshotsFolder(TaskSettings? taskSettings = null, TaskMetadata metadata = null, DateTime? date = null) { date ??= DateTime.Now; var dt = date.Value; @@ -753,7 +751,7 @@ public static async Task OCRImage(Image? image = null, string? filePath return result.Text; } - public static void PinToScreen(TaskSettings taskSettings = null) + public static void PinToScreen(TaskSettings? taskSettings = null) { throw new NotImplementedException("PinToScreen is not implemented"); } @@ -763,7 +761,7 @@ public static void TweetMessage() throw new NotImplementedException("TweetMessage is not implemented"); } - public static EDataType FindDataType(string? filePath, TaskSettings taskSettings) + public static EDataType FindDataType(string? filePath, TaskSettings? taskSettings) { if (FileHelpers.CheckExtension(filePath, taskSettings.AdvancedSettings.ImageExtensions)) { @@ -796,7 +794,7 @@ public static bool CheckFFmpeg(TaskSettings taskSettings) return true; } - public static Screenshot GetScreenshot(TaskSettings taskSettings = null) + public static Screenshot GetScreenshot(TaskSettings? taskSettings = null) { if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); @@ -909,7 +907,7 @@ public static void ImportImageEffect(string? json) } } - public static async Task HandleNativeMessagingInput(string? filePath, TaskSettings taskSettings = null) + public static async Task HandleNativeMessagingInput(string? filePath, TaskSettings? taskSettings = null) { if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath)) { diff --git a/SnapX.Core/Job/TaskInfo.cs b/SnapX.Core/Job/TaskInfo.cs index 7faf072a2..9d62270f6 100644 --- a/SnapX.Core/Job/TaskInfo.cs +++ b/SnapX.Core/Job/TaskInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -10,9 +9,9 @@ using SnapX.Core.Utils.Extensions; namespace SnapX.Core.Job; -public class TaskInfo +public record TaskInfo { - public TaskSettings TaskSettings { get; set; } + public TaskSettings? TaskSettings { get; set; } public string Status { get; set; } public TaskJob Job { get; set; } @@ -126,14 +125,11 @@ public string UploaderHost public Stopwatch UploadDuration { get; set; } - public UploadResult Result { get; set; } + public UploadResult? Result { get; set; } - public TaskInfo(TaskSettings taskSettings) + public TaskInfo(TaskSettings? taskSettings = null) { - if (taskSettings == null) - { - taskSettings = TaskSettings.GetDefaultTaskSettings(); - } + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); TaskSettings = taskSettings; Metadata = new TaskMetadata(); @@ -149,16 +145,15 @@ public TaskInfo(TaskSettings taskSettings) if (!string.IsNullOrEmpty(Metadata.WindowTitle)) { - tags.Add(new HistoryItem.Tag { Text = Metadata.WindowTitle }); + tags.Add(new HistoryItem.Tag { Name = "WindowTitle", Value = Metadata.WindowTitle }); } - // Add ProcessName tag if present if (!string.IsNullOrEmpty(Metadata.ProcessName)) { - tags.Add(new HistoryItem.Tag { Text = Metadata.ProcessName }); + tags.Add(new HistoryItem.Tag { Name = "ProcessName", Value = Metadata.ProcessName }); } - return tags.Count != 0 ? tags : null; + return tags.Count != 0 ? tags : []; } diff --git a/SnapX.Core/Job/TaskManager.cs b/SnapX.Core/Job/TaskManager.cs index 940f13c0b..00684ec67 100644 --- a/SnapX.Core/Job/TaskManager.cs +++ b/SnapX.Core/Job/TaskManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Job/TaskMetadata.cs b/SnapX.Core/Job/TaskMetadata.cs index 9570e031f..27ac79699 100644 --- a/SnapX.Core/Job/TaskMetadata.cs +++ b/SnapX.Core/Job/TaskMetadata.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -11,7 +10,7 @@ public class TaskMetadata : IDisposable { private const int WindowInfoMaxLength = 255; - public Image Image { get; set; } + public Image? Image { get; set; } private string? windowTitle; diff --git a/SnapX.Core/Job/TaskSettings.cs b/SnapX.Core/Job/TaskSettings.cs index 4ff4caf29..529a1d47e 100644 --- a/SnapX.Core/Job/TaskSettings.cs +++ b/SnapX.Core/Job/TaskSettings.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -7,7 +6,8 @@ using System.Text.Json.Serialization; using SixLabors.ImageSharp; using SnapX.Core.Indexer; -using SnapX.Core.ScreenCapture; +using SnapX.Core.Media; +using SnapX.Core.SharpCapture; using SnapX.Core.Upload; using SnapX.Core.Utils; using SnapX.Core.Utils.Extensions; @@ -18,7 +18,7 @@ namespace SnapX.Core.Job; public class TaskSettings { [JsonIgnore] - public TaskSettings TaskSettingsReference { get; private set; } + public TaskSettings? TaskSettingsReference { get; private set; } [JsonIgnore] public bool IsSafeTaskSettings => TaskSettingsReference != null; @@ -132,17 +132,17 @@ public bool IsUsingDefaultSettings } } - public static TaskSettings GetDefaultTaskSettings() + public static TaskSettings? GetDefaultTaskSettings() { - TaskSettings taskSettings = new TaskSettings(); + var taskSettings = new TaskSettings(); taskSettings.SetDefaultSettings(); taskSettings.TaskSettingsReference = SnapX.DefaultTaskSettings; return taskSettings; } - public static TaskSettings GetSafeTaskSettings(TaskSettings taskSettings) + public static TaskSettings? GetSafeTaskSettings(TaskSettings? taskSettings) { - TaskSettings safeTaskSettings; + TaskSettings? safeTaskSettings; if (taskSettings.IsUsingDefaultSettings && SnapX.DefaultTaskSettings != null) { @@ -164,7 +164,7 @@ public void SetDefaultSettings() { if (SnapX.DefaultTaskSettings != null) { - TaskSettings defaultTaskSettings = SnapX.DefaultTaskSettings.Copy(); + TaskSettings? defaultTaskSettings = SnapX.DefaultTaskSettings.Copy(); if (UseDefaultAfterCaptureJob) { @@ -369,7 +369,7 @@ public class TaskSettingsCapture // public FFmpegOptions FFmpegOptions = new FFmpegOptions(); public int ScreenRecordFPS = 30; public int GIFFPS = 15; - public RegionCaptureOptions SurfaceOptions = new RegionCaptureOptions(); + public RegionCaptureOptions SurfaceOptions = new(); public bool ScreenRecordShowCursor = true; public bool ScreenRecordAutoStart = true; public float ScreenRecordStartDelay = 0f; @@ -431,13 +431,13 @@ public class TaskSettingsTools public string ScreenColorPickerFormat = "$hex"; public string ScreenColorPickerFormatCtrl = "$r255, $g255, $b255"; public string ScreenColorPickerInfoText = "RGB: $r255, $g255, $b255$nHex: $hex$nX: $x Y: $y"; - public PinToScreenOptions PinToScreenOptions = new(); + // public PinToScreenOptions PinToScreenOptions = new(); public IndexerSettings IndexerSettings = new(); public ImageBeautifierOptions ImageBeautifierOptions = new(); public ImageCombinerOptions ImageCombinerOptions = new(); public VideoConverterOptions VideoConverterOptions = new(); public VideoThumbnailOptions VideoThumbnailOptions = new(); - public BorderlessWindowSettings BorderlessWindowSettings = new(); + // public BorderlessWindowSettings BorderlessWindowSettings = new(); } public class TaskSettingsAdvanced diff --git a/SnapX.Core/Job/ThreadWorker.cs b/SnapX.Core/Job/ThreadWorker.cs index 3b05d21a4..5f91ab36e 100644 --- a/SnapX.Core/Job/ThreadWorker.cs +++ b/SnapX.Core/Job/ThreadWorker.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Job/WorkerTask.cs b/SnapX.Core/Job/WorkerTask.cs index d8efdcbd9..0ed239b26 100644 --- a/SnapX.Core/Job/WorkerTask.cs +++ b/SnapX.Core/Job/WorkerTask.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,7 +5,6 @@ using System.Text; using System.Text.RegularExpressions; using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; using SnapX.Core.Hotkey; using SnapX.Core.Upload; using SnapX.Core.Upload.BaseServices; @@ -40,24 +38,24 @@ public class WorkerTask : IDisposable public bool StopRequested { get; private set; } public bool RequestSettingUpdate { get; private set; } public bool EarlyURLCopied { get; private set; } - public Stream Data { get; private set; } - public Image Image { get; private set; } + public Stream? Data { get; private set; } + public Image? Image { get; private set; } public bool KeepImage { get; set; } public string? Text { get; private set; } private ThreadWorker threadWorker; - private GenericUploader uploader; + private GenericUploader? uploader; private TaskReferenceHelper taskReferenceHelper; #region Constructors - private WorkerTask(TaskSettings taskSettings) + private WorkerTask(TaskSettings? taskSettings) { Status = TaskStatus.InQueue; Info = new TaskInfo(taskSettings); } - public static WorkerTask CreateDataUploaderTask(EDataType dataType, Stream stream, string? fileName, TaskSettings taskSettings) + public static WorkerTask CreateDataUploaderTask(EDataType dataType, Stream stream, string? fileName, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = TaskJob.DataUpload; @@ -67,7 +65,7 @@ public static WorkerTask CreateDataUploaderTask(EDataType dataType, Stream strea return task; } - public static WorkerTask CreateFileUploaderTask(string? filePath, TaskSettings taskSettings) + public static WorkerTask CreateFileUploaderTask(string? filePath, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.FilePath = filePath; @@ -98,7 +96,7 @@ public static WorkerTask CreateFileUploaderTask(string? filePath, TaskSettings t return task; } - public static WorkerTask CreateImageUploaderTask(TaskMetadata metadata, TaskSettings taskSettings, string customFileName = null) + public static WorkerTask CreateImageUploaderTask(TaskMetadata metadata, TaskSettings? taskSettings, string customFileName = null) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = TaskJob.Job; @@ -118,7 +116,7 @@ public static WorkerTask CreateImageUploaderTask(TaskMetadata metadata, TaskSett return task; } - public static WorkerTask CreateTextUploaderTask(string? text, TaskSettings taskSettings) + public static WorkerTask CreateTextUploaderTask(string? text, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = TaskJob.TextUpload; @@ -128,7 +126,7 @@ public static WorkerTask CreateTextUploaderTask(string? text, TaskSettings taskS return task; } - public static WorkerTask CreateURLShortenerTask(string? url, TaskSettings taskSettings) + public static WorkerTask CreateURLShortenerTask(string? url, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = TaskJob.ShortenURL; @@ -138,7 +136,7 @@ public static WorkerTask CreateURLShortenerTask(string? url, TaskSettings taskSe return task; } - public static WorkerTask CreateShareURLTask(string? url, TaskSettings taskSettings) + public static WorkerTask CreateShareURLTask(string? url, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = TaskJob.ShareURL; @@ -148,7 +146,7 @@ public static WorkerTask CreateShareURLTask(string? url, TaskSettings taskSettin return task; } - public static WorkerTask CreateFileJobTask(string? filePath, TaskMetadata metadata, TaskSettings taskSettings, string customFileName = null) + public static WorkerTask CreateFileJobTask(string? filePath, TaskMetadata metadata, TaskSettings? taskSettings, string customFileName = null) { var task = new WorkerTask(taskSettings); task.Info.FilePath = filePath; @@ -176,7 +174,7 @@ public static WorkerTask CreateFileJobTask(string? filePath, TaskMetadata metada return task; } - public static WorkerTask CreateDownloadTask(string? url, bool upload, TaskSettings taskSettings) + public static WorkerTask CreateDownloadTask(string? url, bool upload, TaskSettings? taskSettings) { WorkerTask task = new WorkerTask(taskSettings); task.Info.Job = upload ? TaskJob.DownloadUpload : TaskJob.Download; @@ -288,10 +286,10 @@ private void ThreadDoWork() Clipboard.Clear(); } - if ((Info.Job == TaskJob.Job || (Info.Job == TaskJob.FileUpload && Info.TaskSettings.AdvancedSettings.UseAfterCaptureTasksDuringFileUpload)) - && Info.TaskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.DeleteFile) && !string.IsNullOrEmpty(Info.FilePath) && System.IO.File.Exists(Info.FilePath)) + if ((Info.Job == TaskJob.Job || (Info.Job == TaskJob.FileUpload && (Info.TaskSettings?.AdvancedSettings.UseAfterCaptureTasksDuringFileUpload ?? true))) + && Info.TaskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.DeleteFile) && !string.IsNullOrEmpty(Info.FilePath) && File.Exists(Info.FilePath)) { - System.IO.File.Delete(Info.FilePath); + File.Delete(Info.FilePath); } } @@ -491,10 +489,7 @@ private void AddErrorMessage(UploaderErrorManager errors) private void AddErrorMessage(string? error) { - if (Info.Result == null) - { - Info.Result = new UploadResult(); - } + Info.Result ??= new UploadResult(); Info.Result.Errors.Add(error); } @@ -671,29 +666,24 @@ private void DoFileJobs() { if (Info.TaskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.PerformActions) && Info.TaskSettings.ExternalPrograms != null) { - IEnumerable actions = Info.TaskSettings.ExternalPrograms.Where(x => x.IsActive); + var actions = Info.TaskSettings.ExternalPrograms.Where(x => x.IsActive); - if (actions.Count() > 0) + if (actions.Any()) { - bool isFileModified = false; - string? fileName = Info.FileName; + var isFileModified = false; + var fileName = Info.FileName; foreach (ExternalProgram fileAction in actions) { - string? modifiedPath = fileAction.Run(Info.FilePath); + var modifiedPath = fileAction.Run(Info.FilePath); - if (!string.IsNullOrEmpty(modifiedPath)) - { - isFileModified = true; - Info.FilePath = modifiedPath; + if (string.IsNullOrEmpty(modifiedPath)) continue; + isFileModified = true; + Info.FilePath = modifiedPath; - if (Data != null) - { - Data.Dispose(); - } + Data?.Dispose(); - fileAction.DeletePendingInputFile(); - } + fileAction.DeletePendingInputFile(); } if (isFileModified) @@ -791,16 +781,7 @@ private void DoAfterUploadJobs() if (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.CopyURLToClipboard)) { - string? txt; - - if (!string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.ClipboardContentFormat)) - { - txt = new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.ClipboardContentFormat); - } - else - { - txt = Info.Result.ToString(); - } + var txt = !string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.ClipboardContentFormat) ? new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.ClipboardContentFormat) : Info.Result.ToString(); if (!string.IsNullOrEmpty(txt)) { @@ -810,16 +791,7 @@ private void DoAfterUploadJobs() if (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.OpenURL)) { - string? result; - - if (!string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.OpenURLFormat)) - { - result = new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.OpenURLFormat); - } - else - { - result = Info.Result.ToString(); - } + var result = !string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.OpenURLFormat) ? new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.OpenURLFormat) : Info.Result.ToString(); URLHelpers.OpenURL(result); } diff --git a/SnapX.Core/Media/Enums.cs b/SnapX.Core/Media/Enums.cs index e4f31497f..a56181466 100644 --- a/SnapX.Core/Media/Enums.cs +++ b/SnapX.Core/Media/Enums.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/GradientInfo.cs b/SnapX.Core/Media/GradientInfo.cs new file mode 100644 index 000000000..b65cfb6a9 --- /dev/null +++ b/SnapX.Core/Media/GradientInfo.cs @@ -0,0 +1,136 @@ +using System.ComponentModel; +using System.Text.Json.Serialization; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SnapX.Core.Utils; + +namespace SnapX.Core.Media; + +public enum LinearGradientMode +{ + Horizontal, + Vertical +} + +public record GradientStop(Color Color, float Location) +{ + public Color Color { get; set; } = Color; + public float Location { get; set; } = Location; // 0-100 +} + +public class GradientInfo(LinearGradientMode Type) +{ + [DefaultValue(LinearGradientMode.Vertical)] + public LinearGradientMode Type { get; set; } = Type; + + /// + /// Gradient color stops, each with a Ratio in [0,1] + /// + public List Colors { get; set; } = new(); + + [JsonIgnore] + public bool IsValid => Colors is { Count: > 0 }; + + [JsonIgnore] + public bool IsVisible => IsValid && Colors.Any(x => x.Color.ToPixel().A > 0); + + [JsonIgnore] + public bool IsTransparent => IsValid && Colors.Any(x => x.Color.ToPixel().A < 255); + + public GradientInfo() : this(LinearGradientMode.Vertical) { } + + public GradientInfo(LinearGradientMode type, params ColorStop[] colors) : this(type) + { + Colors = colors.ToList(); + } + + public GradientInfo(LinearGradientMode type, params Color[] colors) : this(type) + { + var count = colors.Length; + for (var i = 0; i < count; i++) + { + var ratio = (count == 1) ? 0f : i / (float)(count - 1); + Colors.Add(new ColorStop(ratio, colors[i])); + } + } + + public GradientInfo(params ColorStop[] colors) : this(LinearGradientMode.Vertical, colors) { } + + public GradientInfo(params Color[] colors) : this(LinearGradientMode.Vertical, colors) { } + + public void Clear() + { + Colors.Clear(); + } + + public void Sort() + { + Colors.Sort((x, y) => x.Ratio.CompareTo(y.Ratio)); + } + + public void Reverse() + { + Colors = Colors + .Select(s => new ColorStop(1f - s.Ratio, s.Color)) + .OrderBy(s => s.Ratio) + .ToList(); + } + + /// + /// Returns an ImageSharp LinearGradientBrush based on this gradient info. + /// + public Brush GetGradientBrush(RectangleF rect) + { + var stops = Colors + .OrderBy(x => x.Ratio) + .ToArray(); + + if (stops.All(x => x.Ratio != 0f)) + { + var first = stops.FirstOrDefault(); + stops = new[] { new ColorStop(0f, first.Color) }.Concat(stops).ToArray(); + } + + if (stops.All(x => x.Ratio != 1f)) + { + var last = stops.LastOrDefault(); + stops = stops.Append(new ColorStop(1f, last.Color)).ToArray(); + } + + var start = new PointF(rect.Left, rect.Top); + + var end = Type == LinearGradientMode.Horizontal + ? new PointF(rect.Right, rect.Top) + : new PointF(rect.Left, rect.Bottom); + + return new LinearGradientBrush(start, end, GradientRepetitionMode.Repeat, stops); + } + + public Image CreateGradientPreview(int width, int height, bool border = false, bool checkers = false) + { + var image = new Image(width, height); + + if (checkers && IsTransparent) + { + ImageHelpers.DrawCheckerPattern(image, 10, [Color.LightGray, Color.White]); + } + + var brush = GetGradientBrush(new RectangleF(0, 0, width, height)); + + image.Mutate(ctx => + { + ctx.Fill(brush); + + if (border) + { + ctx.Draw(Color.Black, 1, new RectangleF(0, 0, width - 1, height - 1)); + } + }); + + return image; + } + + public override string ToString() => "Gradient"; +} diff --git a/SnapX.Core/Media/ImageBeautifierOptions.cs b/SnapX.Core/Media/ImageBeautifierOptions.cs new file mode 100644 index 000000000..a8fa37aea --- /dev/null +++ b/SnapX.Core/Media/ImageBeautifierOptions.cs @@ -0,0 +1,47 @@ +using SixLabors.ImageSharp; + +namespace SnapX.Core.Media; + +public class ImageBeautifierOptions +{ + public int Margin { get; set; } + public int Padding { get; set; } + public bool SmartPadding { get; set; } + public int RoundedCorner { get; set; } + public int ShadowRadius { get; set; } + public int ShadowOpacity { get; set; } + public int ShadowDistance { get; set; } + public int ShadowAngle { get; set; } + public Color ShadowColor { get; set; } + public ImageBeautifierBackgroundType BackgroundType { get; set; } + public GradientInfo BackgroundGradient { get; set; } + public Color BackgroundColor { get; set; } + public string BackgroundImageFilePath { get; set; } + + public ImageBeautifierOptions() + { + ResetOptions(); + } + + public void ResetOptions() + { + Margin = 80; + Padding = 40; + SmartPadding = true; + RoundedCorner = 20; + ShadowRadius = 30; + ShadowOpacity = 80; + ShadowDistance = 10; + ShadowAngle = 180; + ShadowColor = Color.Black; + BackgroundType = ImageBeautifierBackgroundType.Gradient; + BackgroundGradient = new GradientInfo( + LinearGradientMode.Horizontal, + Color.FromRgba(255, 81, 47, 255), + Color.FromRgba(221, 36, 118, 255) + ); + + BackgroundColor = Color.FromRgba(34, 34, 34, 255); + BackgroundImageFilePath = ""; + } +} diff --git a/SnapX.Core/Media/ImageCombinerOptions.cs b/SnapX.Core/Media/ImageCombinerOptions.cs index 19d66ad65..340a62008 100644 --- a/SnapX.Core/Media/ImageCombinerOptions.cs +++ b/SnapX.Core/Media/ImageCombinerOptions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/ScreenRecordManager.cs b/SnapX.Core/Media/ScreenRecordManager.cs index 54ae5379c..0c0976854 100644 --- a/SnapX.Core/Media/ScreenRecordManager.cs +++ b/SnapX.Core/Media/ScreenRecordManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/Screenshot_Transparent.cs b/SnapX.Core/Media/Screenshot_Transparent.cs index 58cf0bd40..b917e1441 100644 --- a/SnapX.Core/Media/Screenshot_Transparent.cs +++ b/SnapX.Core/Media/Screenshot_Transparent.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/VideoConverterOptions.cs b/SnapX.Core/Media/VideoConverterOptions.cs index 2c61992a7..a0db5455a 100644 --- a/SnapX.Core/Media/VideoConverterOptions.cs +++ b/SnapX.Core/Media/VideoConverterOptions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/VideoInfo.cs b/SnapX.Core/Media/VideoInfo.cs index 8048dc688..597a1a42a 100644 --- a/SnapX.Core/Media/VideoInfo.cs +++ b/SnapX.Core/Media/VideoInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/VideoThumbnailInfo.cs b/SnapX.Core/Media/VideoThumbnailInfo.cs index fab83447b..a07a077b6 100644 --- a/SnapX.Core/Media/VideoThumbnailInfo.cs +++ b/SnapX.Core/Media/VideoThumbnailInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/VideoThumbnailOptions.cs b/SnapX.Core/Media/VideoThumbnailOptions.cs index 0af393fcf..d5c822ad3 100644 --- a/SnapX.Core/Media/VideoThumbnailOptions.cs +++ b/SnapX.Core/Media/VideoThumbnailOptions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Media/VideoThumbnailer.cs b/SnapX.Core/Media/VideoThumbnailer.cs index 3cdd8d4e1..e67faea8b 100644 --- a/SnapX.Core/Media/VideoThumbnailer.cs +++ b/SnapX.Core/Media/VideoThumbnailer.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Models/SavedConfiguration.cs b/SnapX.Core/Models/SavedConfiguration.cs deleted file mode 100644 index 440ece770..000000000 --- a/SnapX.Core/Models/SavedConfiguration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - - -namespace SnapX.Core.Models; - -[Table("ApplicationConfig")] -public record SavedConfiguration -{ - [Key] - public int Id { get; set; } - - public string ConfigSection { get; set; } - - public string SettingKey { get; set; } - - public string SettingValue { get; set; } - - public string DataType { get; set; } - - public DateTime UpdatedAt { get; set; } -} diff --git a/SnapX.Core/OSX.props b/SnapX.Core/OSX.props index 6056f8154..9dc0bc302 100644 --- a/SnapX.Core/OSX.props +++ b/SnapX.Core/OSX.props @@ -1,10 +1,7 @@ - - libsnapxrust.dylib - - + diff --git a/SnapX.Core/ObservableSink.cs b/SnapX.Core/ObservableSink.cs new file mode 100644 index 000000000..a4285b718 --- /dev/null +++ b/SnapX.Core/ObservableSink.cs @@ -0,0 +1,31 @@ +using Serilog.Core; +using Serilog.Events; + +namespace SnapX.Core; + +public class ObservableSink(IFormatProvider? FormatProvider = null) : ILogEventSink +{ + private readonly List _buffer = []; + private readonly Lock _lock = new(); + + public event EventHandler? LogMessageReceived; + + public void Emit(LogEvent logEvent) + { + + lock (_lock) + { + _buffer.Add(logEvent); + } + + LogMessageReceived?.Invoke(this, logEvent); + } + + public List GetBufferedEvents() + { + lock (_lock) + { + return _buffer; + } + } +} diff --git a/SnapX.Core/Services/SerilogLoggerService.cs b/SnapX.Core/Services/SerilogLoggerService.cs new file mode 100644 index 000000000..a70c7b86c --- /dev/null +++ b/SnapX.Core/Services/SerilogLoggerService.cs @@ -0,0 +1,79 @@ +using Microsoft.Extensions.Configuration; +using Serilog; +using Serilog.Context; +using Serilog.Sinks.SystemConsole.Themes; +using SnapX.Core.Interfaces; + +namespace SnapX.Core.Services; +public class SerilogLogService : ILoggerService +{ + private readonly ILogger _logger; + + public SerilogLogService( + string? logFilePath, + bool logToConsole, + IConfiguration? config = null) + { + var loggerConfig = new LoggerConfiguration(); + +#if DEBUG + loggerConfig.MinimumLevel.Debug(); +#else + loggerConfig.MinimumLevel.Information(); +#endif + + if (!string.IsNullOrWhiteSpace(logFilePath)) + { + loggerConfig = loggerConfig + .WriteTo.Async(a => a.File( + logFilePath, + rollingInterval: RollingInterval.Day, + buffered: true, + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}]: {Message:lj}{NewLine}{Exception}" + )); + } + + if (logToConsole) + { + loggerConfig = loggerConfig + .WriteTo.Console(theme: AnsiConsoleTheme.Sixteen); + } + + if (config is not null) + { + loggerConfig.ReadFrom.Configuration(config); + } + + _logger = loggerConfig.CreateLogger(); + } + + public SerilogLogService(ILogger Logger) + { + _logger = Logger; + } + public ILogScope BeginScope(string name) + { + return new SerilogLogScope(LogContext.PushProperty("Scope", name)); + } + public void Debug(string messageTemplate, params object[] args) => + _logger.Debug(messageTemplate, args); + + public void Information(string messageTemplate, params object[] args) => + _logger.Information(messageTemplate, args); + + public void Warning(string messageTemplate, params object[] args) => + _logger.Warning(messageTemplate, args); + + public void Error(Exception exception, string messageTemplate, params object[] args) => + _logger.Error(exception, messageTemplate, args); + + public void Error(string messageTemplate, params object[] args) => + _logger.Error(messageTemplate, args); + private class SerilogLogScope(IDisposable InnerScope) : ILogScope + { + public void Dispose() + { + InnerScope.Dispose(); + } + } +} diff --git a/SnapX.Core/SettingManager.cs b/SnapX.Core/SettingManager.cs index 8b1dd357e..5bf0c3af2 100644 --- a/SnapX.Core/SettingManager.cs +++ b/SnapX.Core/SettingManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -12,6 +11,7 @@ using Esatto.Win32.Registry; #endif using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using SnapX.Core.History; using SnapX.Core.Hotkey; using SnapX.Core.Job; @@ -22,13 +22,13 @@ namespace SnapX.Core; -[JsonSerializable(typeof(RootConfiguration))] +[JsonSerializable(typeof(ApplicationConfig))] [JsonSerializable(typeof(IConfiguration))] [JsonSerializable(typeof(UploadersConfig))] [JsonSerializable(typeof(HotkeysConfig))] internal partial class SettingsContext : JsonSerializerContext; -internal static class SettingManager +internal class SettingManager(IServiceProvider serviceProvider) { private const string ApplicationConfigFileName = "ApplicationConfig.json"; @@ -90,21 +90,20 @@ private static string HotkeysConfigFilePath public static string? SnapshotFolder => Path.Combine(SnapX.PersonalFolder, "Snapshots"); - private static RootConfiguration Settings { get => SnapX.Settings; set => SnapX.Settings = value; } - private static TaskSettings DefaultTaskSettings { get => SnapX.DefaultTaskSettings; set => SnapX.DefaultTaskSettings = value; } + private static ApplicationConfig Settings { get => SnapX.Settings; set => SnapX.Settings = value; } + private static TaskSettings? DefaultTaskSettings { get => SnapX.DefaultTaskSettings; set => SnapX.DefaultTaskSettings = value; } private static UploadersConfig UploadersConfig { get => SnapX.UploadersConfig; set => SnapX.UploadersConfig = value; } private static HotkeysConfig HotkeysConfig { get => SnapX.HotkeysConfig; set => SnapX.HotkeysConfig = value; } - private static VersionEnforcer theLaw; + private static VersionEnforcer? theLaw; private static ManualResetEvent uploadersConfigResetEvent = new(false); private static ManualResetEvent hotkeysConfigResetEvent = new(false); [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] - public static void LoadSettings() + public void LoadSettings() { - theLaw = new VersionEnforcer(SnapX.LockDirectory); + theLaw = serviceProvider.GetRequiredService(); theLaw.Enforce(); - LoadApplicationConfig(); LoadUploadersConfig(); LoadHotkeysConfig(); } @@ -150,7 +149,7 @@ public static void LoadApplicationConfig(bool fallbackSupport = true) { // DebugHelper.WriteLine($"{kv.Key} = {kv.Value}"); } - var settings = new RootConfiguration(); + var settings = new ApplicationConfig(); SnapX.Configuration.Bind(settings); Settings = settings; if (string.IsNullOrWhiteSpace(Settings.SQLitePath)) @@ -203,60 +202,6 @@ public static void LoadHotkeysConfig(bool fallbackSupport = true) HotkeysConfigBackwardCompatibilityTasks(); } - // private static void MigrateApplicationConfigJSONToSQLite() - // { - // try - // { - // DebugHelper.WriteLine($"JSON -> SQLite Migration: Migrating {ApplicationConfigFileName} at {ApplicationConfigFilePath}"); - // var json = File.ReadAllText(ApplicationConfigFilePath); - // var node = JsonNode.Parse(json)!.AsObject(); - // node.Remove("RecentTasks"); - // - // var nodeJSON = node.ToJsonString(); - // - // var root = JsonDocument.Parse(nodeJSON).RootElement; - // foreach (var property in root.EnumerateObject()) - // { - // var key = property.Name; - // var value = property.Value; - // - // switch (value.ValueKind) - // { - // case JsonValueKind.Object: - // FlattenAndInsert(value, key); - // break; - // - // case JsonValueKind.Array: - // var index = 0; - // foreach (var item in value.EnumerateArray()) - // { - // // Compose a "key:index" prefix for each item and recurse - // FlattenAndInsert(item, $"{key}:{index++}"); - // } - // - // break; - // - // case JsonValueKind.String: - // case JsonValueKind.Number: - // case JsonValueKind.True: - // case JsonValueKind.False: - // case JsonValueKind.Null: - // case JsonValueKind.Undefined: - // default: - // FlattenAndInsert(value, key); - // break; - // } - // } - // var migratedPath = ApplicationConfigFilePath + ".migrated"; - // var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - // migratedPath = ApplicationConfigFilePath + $"{timestamp}.migrated"; - // File.Move(ApplicationConfigFilePath, migratedPath); - // } - // catch (Exception ex) - // { - // DebugHelper.WriteException(ex); - // } - // } public static void SaveApplicationConfig() { if (SnapX.Sandbox) @@ -270,7 +215,8 @@ public static void SaveApplicationConfig() { WriteIndented = true, TypeInfoResolver = SettingsContext.Default, - DefaultIgnoreCondition = JsonIgnoreCondition.Never + DefaultIgnoreCondition = JsonIgnoreCondition.Never, + Converters = { new JsonStringEnumConverter() } }); File.WriteAllText(configFilePath, json); } @@ -291,7 +237,9 @@ public static void SaveUploadConfig() var json = JsonSerializer.Serialize(UploadersConfig, new JsonSerializerOptions { WriteIndented = true, - TypeInfoResolver = SettingsContext.Default + TypeInfoResolver = SettingsContext.Default, + Converters = { new JsonStringEnumConverter() } + }); File.WriteAllText(configFilePath, json); } @@ -312,7 +260,8 @@ public static void SaveHotkeysConfig() var json = JsonSerializer.Serialize(HotkeysConfig, new JsonSerializerOptions { WriteIndented = true, - TypeInfoResolver = SettingsContext.Default + TypeInfoResolver = SettingsContext.Default, + Converters = { new JsonStringEnumConverter() } }); File.WriteAllText(configFilePath, json); } @@ -333,6 +282,12 @@ private static void ApplicationConfigBackwardCompatibilityTasks() .OrderBy(name => name) // Ensure migrations are processed in numerical order .ToList(); + if (SnapX.DbConnection is null) + { + DebugHelper.WriteLine("SnapX.DbConnection is null, skipping backward compatibility tasks."); + return; + } + // Ensure MigrationLog table exists for the checks below // This is crucial if it's the very first time running migrations. SnapX.DbConnection.Execute(@" @@ -524,21 +479,9 @@ private static void UploadersConfigBackwardCompatibilityTasks() private static void HotkeysConfigBackwardCompatibilityTasks() { - - // if (Settings.IsUpgradeFrom("15.0.1")) - // { - // foreach (var taskSettings in HotkeysConfig.Hotkeys.Select(x => x.TaskSettings)) - // { - // if (tasktaskSettings.CaptureSettings != null) - // { - // // taskSettings.CaptureSettings.ScrollingCaptureOptions = new ScrollingCaptureOptions(); - // // taskSettings.CaptureSettings.FFmpegOptions.FixSources(); - // } - // } - // } } - public static void Dispose() => theLaw.Dispose(); + public static void Dispose() => theLaw?.Dispose(); public static void CleanupHotkeysConfig() { foreach (var taskSettings in HotkeysConfig.Hotkeys.Select(x => x.TaskSettings)) @@ -653,27 +596,5 @@ public static bool Import(string archivePath) return false; } - - // This method validates the setting before restoration to ensure it fits the defined type - private static bool IsValidValue(string value, string dataType) - { - if (string.IsNullOrWhiteSpace(value)) - return false; // Prevent null or empty values. - - switch (dataType) - { - case "int": - return int.TryParse(value, out _); - case "double": - return double.TryParse(value, out _); - case "bool": - return bool.TryParse(value, out _); - case "string": - return true; - default: - DebugHelper.WriteLine($"Unknown data type: {dataType}"); - return false; - } - } } diff --git a/SnapX.Core/ScreenCapture/Animations/BaseAnimation.cs b/SnapX.Core/SharpCapture/Animations/BaseAnimation.cs similarity index 94% rename from SnapX.Core/ScreenCapture/Animations/BaseAnimation.cs rename to SnapX.Core/SharpCapture/Animations/BaseAnimation.cs index f4fa50d87..2d777f61f 100644 --- a/SnapX.Core/ScreenCapture/Animations/BaseAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/BaseAnimation.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Diagnostics; -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class BaseAnimation { diff --git a/SnapX.Core/ScreenCapture/Animations/ColorBlinkAnimation.cs b/SnapX.Core/SharpCapture/Animations/ColorBlinkAnimation.cs similarity index 95% rename from SnapX.Core/ScreenCapture/Animations/ColorBlinkAnimation.cs rename to SnapX.Core/SharpCapture/Animations/ColorBlinkAnimation.cs index 472299490..d7792bb54 100644 --- a/SnapX.Core/ScreenCapture/Animations/ColorBlinkAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/ColorBlinkAnimation.cs @@ -1,11 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; using SnapX.Core.Utils; -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class ColorBlinkAnimation : BaseAnimation { diff --git a/SnapX.Core/ScreenCapture/Animations/OpacityAnimation.cs b/SnapX.Core/SharpCapture/Animations/OpacityAnimation.cs similarity index 95% rename from SnapX.Core/ScreenCapture/Animations/OpacityAnimation.cs rename to SnapX.Core/SharpCapture/Animations/OpacityAnimation.cs index 33ad1e598..5062e1dc1 100644 --- a/SnapX.Core/ScreenCapture/Animations/OpacityAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/OpacityAnimation.cs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class OpacityAnimation : BaseAnimation { diff --git a/SnapX.Core/ScreenCapture/Animations/PointAnimation.cs b/SnapX.Core/SharpCapture/Animations/PointAnimation.cs similarity index 94% rename from SnapX.Core/ScreenCapture/Animations/PointAnimation.cs rename to SnapX.Core/SharpCapture/Animations/PointAnimation.cs index 8d8fa17e5..e8b322fcf 100644 --- a/SnapX.Core/ScreenCapture/Animations/PointAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/PointAnimation.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class PointAnimation : BaseAnimation { diff --git a/SnapX.Core/ScreenCapture/Animations/RectangleAnimation.cs b/SnapX.Core/SharpCapture/Animations/RectangleAnimation.cs similarity index 95% rename from SnapX.Core/ScreenCapture/Animations/RectangleAnimation.cs rename to SnapX.Core/SharpCapture/Animations/RectangleAnimation.cs index bbb847fb2..d7341f749 100644 --- a/SnapX.Core/ScreenCapture/Animations/RectangleAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/RectangleAnimation.cs @@ -1,11 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; using SnapX.Core.Utils; -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class RectangleAnimation : BaseAnimation { diff --git a/SnapX.Core/ScreenCapture/Animations/TextAnimation.cs b/SnapX.Core/SharpCapture/Animations/TextAnimation.cs similarity index 80% rename from SnapX.Core/ScreenCapture/Animations/TextAnimation.cs rename to SnapX.Core/SharpCapture/Animations/TextAnimation.cs index 0aa338fa2..f33cede58 100644 --- a/SnapX.Core/ScreenCapture/Animations/TextAnimation.cs +++ b/SnapX.Core/SharpCapture/Animations/TextAnimation.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Drawing; -namespace SnapX.Core.ScreenCapture.Animations; +namespace SnapX.Core.SharpCapture.Animations; internal class TextAnimation : OpacityAnimation { diff --git a/SnapX.Core/SharpCapture/BaseCapture.cs b/SnapX.Core/SharpCapture/BaseSharpCapture.cs similarity index 72% rename from SnapX.Core/SharpCapture/BaseCapture.cs rename to SnapX.Core/SharpCapture/BaseSharpCapture.cs index 3575fe015..105046af1 100644 --- a/SnapX.Core/SharpCapture/BaseCapture.cs +++ b/SnapX.Core/SharpCapture/BaseSharpCapture.cs @@ -1,19 +1,21 @@ using SixLabors.ImageSharp; +using SnapX.Core.Job; + #pragma warning disable CS1998 namespace SnapX.Core.SharpCapture; -public abstract class BaseCapture +public abstract class BaseSharpCapture { - public virtual async Task CaptureScreen(Rectangle bounds) => + public virtual async Task CaptureScreen(Rectangle bounds, TaskSettings? taskSettings = null) => throw new NotImplementedException("SharpCapture CaptureScreen is not implemented."); - public virtual async Task CaptureScreen(Point? pos) => + public virtual async Task CaptureScreen(Point? pos, TaskSettings? taskSettings = null) => throw new NotImplementedException("SharpCapture CaptureScreen is not implemented."); - public virtual async Task CaptureWindow(Point pos) => + public virtual async Task CaptureWindow(Point pos, TaskSettings? taskSettings = null) => throw new NotImplementedException("SharpCapture CaptureWindow is not implemented."); - public virtual async Task CaptureRectangle(Rectangle rect) => + public virtual async Task CaptureRectangle(Rectangle rect, TaskSettings? taskSettings = null) => throw new NotImplementedException("SharpCapture CaptureRectangle is not implemented."); - public virtual async Task CaptureFullscreen() => + public virtual async Task CaptureFullscreen(TaskSettings? taskSettings = null) => throw new NotImplementedException("SharpCapture CaptureFullscreen is not implemented."); public virtual async Task GetWorkingArea() => throw new NotImplementedException("SharpCapture GetWorkingArea is not implemented."); diff --git a/SnapX.Core/SharpCapture/CaptureActiveMonitor.cs b/SnapX.Core/SharpCapture/CaptureActiveMonitor.cs new file mode 100644 index 000000000..4ce65dfb9 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureActiveMonitor.cs @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; + +public class CaptureActiveMonitor( + IMainWindowService MainWindowService, + INotificationService NotificationService, + IUploadManager UploadManager, + IDelayService DelayService, + ILoggerService _logger, + ICaptureService CaptureService) + : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, _logger, CaptureService) +{ + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + _logger.Debug("CaptureActiveMonitor started"); + + var img = await _captureService + .CaptureActiveMonitorAsync(taskSettings) + .ConfigureAwait(false); + if (img is null) + { + _logger.Debug("CaptureActiveMonitorAsync returned null. Returning empty TaskMetadata"); + return new TaskMetadata(); + } + var metadata = CreateMetadata(img.Bounds); + metadata.Image = img; + return metadata; + } +} diff --git a/SnapX.Core/SharpCapture/CaptureActiveWindow.cs b/SnapX.Core/SharpCapture/CaptureActiveWindow.cs new file mode 100644 index 000000000..129806d3b --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureActiveWindow.cs @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; +public class CaptureActiveWindow( + IMainWindowService MainWindowService, + INotificationService NotificationService, + IUploadManager UploadManager, + IDelayService DelayService, + ILoggerService LoggerService, + ICaptureService CaptureService) + : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) +{ + + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + var metadata = CreateMetadata(); + + if (taskSettings.CaptureSettings is { CaptureTransparent: true, CaptureClientArea: false }) + { + LoggerService.Debug("Capture transparent mode is default now. Non transparent mode is not implemented"); + } + + metadata.Image = await _captureService.CaptureActiveWindowAsync(); + + return metadata; + } +} diff --git a/SnapX.Core/SharpCapture/CaptureBase.cs b/SnapX.Core/SharpCapture/CaptureBase.cs new file mode 100644 index 000000000..345caa05a --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureBase.cs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SixLabors.ImageSharp; +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; +using SnapX.Core.Utils.Extensions; +using SnapX.Core.Utils.Native; + +namespace SnapX.Core.SharpCapture; +public abstract class CaptureBase( + IMainWindowService MainWindowService, + INotificationService NotificationService, + IUploadManager UploadManager, + IDelayService DelayService, + ILoggerService LoggerService, + ICaptureService CaptureService) +{ + public bool AllowAutoHideForm { get; set; } = true; + public bool AllowAnnotation { get; set; } = true; + + internal readonly ICaptureService _captureService = CaptureService; + + public async Task CaptureAsync(TaskSettings? taskSettings = null, bool autoHideForm = false) + { + using (LoggerService.BeginScope("Capture")) + { + if (taskSettings == null) + { + taskSettings = TaskSettings.GetDefaultTaskSettings(); + LoggerService.Debug("Loaded default task settings"); + } + + if (taskSettings.CaptureSettings.ScreenshotDelay > 0) + { + var delay = (int)(taskSettings.CaptureSettings.ScreenshotDelay * 1000); + LoggerService.Information("Delaying capture for {Delay} ms as configured", delay); + await DelayService.DelayAsync(delay); + } + + await CaptureInternalAsync(taskSettings, autoHideForm); + } + } + + private async Task CaptureInternalAsync(TaskSettings taskSettings, bool autoHideForm) + { + using (LoggerService.BeginScope("CaptureInternal")) + { + if (autoHideForm && AllowAutoHideForm) + { + LoggerService.Debug("Hiding main window for capture"); + await MainWindowService.HideAsync(); + await DelayService.DelayAsync(250); + } + + TaskMetadata? metadata = null; + + try + { + AllowAnnotation = true; + LoggerService.Debug("Executing capture logic in {CaptureType}", GetType().Name); + metadata = await ExecuteAsync(taskSettings); + } + catch (Exception ex) + { + LoggerService.Error(ex, "An error occurred during capture"); + } + finally + { + if (autoHideForm && AllowAutoHideForm) + { + LoggerService.Debug("Re-activating main window after capture"); + await MainWindowService.ForceActivateAsync(); + } + + await AfterCaptureAsync(metadata, taskSettings); + } + } + } + + protected virtual async Task AfterCaptureAsync(TaskMetadata? metadata, TaskSettings taskSettings) + { + using (LoggerService.BeginScope("AfterCapture")) + { + if (metadata is { Image: not null }) + { + LoggerService.Debug("Running AfterCapture tasks"); + + await NotificationService + .PlayNotificationSoundAsync(NotificationSound.Capture, taskSettings); + + if (taskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.AnnotateImage) && !AllowAnnotation) + { + taskSettings.AfterCaptureJob = + taskSettings.AfterCaptureJob.Remove(AfterCaptureTasks.AnnotateImage); + + LoggerService.Information("Annotation disabled. Removed AnnotateImage from AfterCapture tasks"); + } + + if (taskSettings.ImageSettings.ImageEffectOnlyRegionCapture && + GetType() != typeof(CaptureRegion) && GetType() != typeof(CaptureLastRegion)) + { + taskSettings.AfterCaptureJob = + taskSettings.AfterCaptureJob.Remove(AfterCaptureTasks.AddImageEffects); + + LoggerService.Information("Skipped image effects because ImageEffectOnlyRegionCapture is true"); + } + + await UploadManager.RunImageTaskAsync(metadata, taskSettings); + LoggerService.Information("Upload service completed image processing"); + } + else + { + LoggerService.Warning("No image captured. Skipping AfterCapture tasks"); + } + } + } + + protected abstract Task ExecuteAsync(TaskSettings taskSettings); + + protected TaskMetadata CreateMetadata() + { + return CreateMetadata(Rectangle.Empty, null); + } + + protected TaskMetadata CreateMetadata(Rectangle insideRect, string? ignoreProcess = "explorer") + { + var metadata = new TaskMetadata(); + + var windowInfo = Methods.GetForegroundWindow(); + if ((ignoreProcess == null || !windowInfo.ProcessName.Equals(ignoreProcess, StringComparison.OrdinalIgnoreCase)) && + (insideRect.IsEmpty || windowInfo.Rectangle.Contains(insideRect))) + { + metadata.UpdateInfo(windowInfo); + LoggerService.Debug("Foreground window info added to capture metadata: {ProcessName}", windowInfo.ProcessName); + } + else + { + LoggerService.Debug("Window info skipped because it didn't match criteria. IgnoreProcess={IgnoreProcess}", ignoreProcess ?? string.Empty); + } + + return metadata; + } +} diff --git a/SnapX.Core/SharpCapture/CaptureCustomRegion.cs b/SnapX.Core/SharpCapture/CaptureCustomRegion.cs new file mode 100644 index 000000000..d2e8671f8 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureCustomRegion.cs @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; + +public class CaptureCustomRegion(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService) : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) +{ + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + var rect = taskSettings.CaptureSettings.CaptureCustomRegion; + var metadata = CreateMetadata(rect); + metadata.Image = await _captureService.CaptureRectangle(taskSettings, rect); + return metadata; + } +} + diff --git a/SnapX.Core/SharpCapture/CaptureCustomWindow.cs b/SnapX.Core/SharpCapture/CaptureCustomWindow.cs new file mode 100644 index 000000000..7d397ba52 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureCustomWindow.cs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; +public class CaptureCustomWindow(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService, IntPtr? WindowHandle) : CaptureWindow(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService, WindowHandle) +{ + // protected override TaskMetadata Execute(TaskSettings? taskSettings) + // { + // string windowTitle = taskSettings.CaptureSettings.CaptureCustomWindow; + // + // if (!string.IsNullOrEmpty(windowTitle)) + // { + // // TODO: Reimplement w/ Windows support & Linux (X11, and KDE Plasma Wayland) + // // IntPtr hWnd = NativeMethods.SearchWindow(windowTitle); + // // + // // if (hWnd == IntPtr.Zero) + // // { + // // MessageBox.Show(Resources.UnableToFindAWindowWithSpecifiedWindowTitle, "SnapX", MessageBoxButtons.OK, MessageBoxIcon.Information); + // // } + // // else + // // { + // // WindowHandle = hWnd; + // // + // // return base.Execute(taskSettings); + // // } + // } + // + // return null; + // } +} + diff --git a/SnapX.Core/SharpCapture/CaptureFullscreen.cs b/SnapX.Core/SharpCapture/CaptureFullscreen.cs new file mode 100644 index 000000000..df7b3e51a --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureFullscreen.cs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; + +public class CaptureFullscreen(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService) : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) +{ + // protected override TaskMetadata Execute(TaskSettings? taskSettings) + // { + // DebugHelper.WriteLine("CaptureFullscreen"); + // var img = TaskHelpers.GetScreenshot(taskSettings).CaptureFullscreen(); + // var metadata = CreateMetadata(img.Bounds); + // metadata.Image = img; + // + // return metadata; + // } + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + throw new NotImplementedException(); + } +} + diff --git a/SnapX.Core/SharpCapture/CaptureLastRegion.cs b/SnapX.Core/SharpCapture/CaptureLastRegion.cs new file mode 100644 index 000000000..9d5bfeeb0 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureLastRegion.cs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; +public class CaptureLastRegion(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService, RegionCaptureType RegionCaptureType) : CaptureRegion(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService, RegionCaptureType) +{ + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + throw new NotImplementedException(); + } + // protected override TaskMetadata Execute(TaskSettings taskSettings) + // { + // switch (lastRegionCaptureType) + // { + // default: + // case RegionCaptureType.Default: return ExecuteRegionCapture(taskSettings); + // case RegionCaptureType.Light: return ExecuteRegionCaptureLight(taskSettings); + // case RegionCaptureType.Transparent: return ExecuteRegionCaptureTransparent(taskSettings); + // } + // } +} + diff --git a/SnapX.Core/SharpCapture/CaptureMonitor.cs b/SnapX.Core/SharpCapture/CaptureMonitor.cs new file mode 100644 index 000000000..e8a2faba2 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureMonitor.cs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SixLabors.ImageSharp; +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; +public class CaptureMonitor(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService, Rectangle MonitorRectangle) : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) +{ + public Rectangle MonitorRectangle { get; private set; } = MonitorRectangle; + + + // protected override TaskMetadata Execute(TaskSettings taskSettings) + // { + // DebugHelper.WriteLine("CaptureMonitor Start"); + // var metadata = CreateMetadata(MonitorRectangle); + // metadata.Image = TaskHelpers.GetScreenshot().CaptureRectangle(MonitorRectangle); + // return metadata; + // } + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + throw new NotImplementedException(); + } +} + diff --git a/SnapX.Core/Capture/CaptureRegion.cs b/SnapX.Core/SharpCapture/CaptureRegion.cs similarity index 77% rename from SnapX.Core/Capture/CaptureRegion.cs rename to SnapX.Core/SharpCapture/CaptureRegion.cs index 8828e97c7..08741764a 100644 --- a/SnapX.Core/Capture/CaptureRegion.cs +++ b/SnapX.Core/SharpCapture/CaptureRegion.cs @@ -1,38 +1,30 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using SnapX.Core.Interfaces; using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; -namespace SnapX.Core.Capture; -public class CaptureRegion : CaptureBase +namespace SnapX.Core.SharpCapture; +public class CaptureRegion(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService, RegionCaptureType RegionCaptureType) : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) { protected static RegionCaptureType lastRegionCaptureType = RegionCaptureType.Default; - public RegionCaptureType RegionCaptureType { get; protected set; } - - public CaptureRegion() - { - } - - public CaptureRegion(RegionCaptureType regionCaptureType) - { - RegionCaptureType = regionCaptureType; - } + public RegionCaptureType RegionCaptureType { get; protected set; } = RegionCaptureType; - protected override TaskMetadata Execute(TaskSettings taskSettings) - { - switch (RegionCaptureType) - { - default: - case RegionCaptureType.Default: - return ExecuteRegionCapture(taskSettings); - case RegionCaptureType.Light: - return ExecuteRegionCaptureLight(taskSettings); - case RegionCaptureType.Transparent: - return ExecuteRegionCaptureTransparent(taskSettings); - } - } + // protected override TaskMetadata Execute(TaskSettings taskSettings) + // { + // switch (RegionCaptureType) + // { + // default: + // case RegionCaptureType.Default: + // return ExecuteRegionCapture(taskSettings); + // case RegionCaptureType.Light: + // return ExecuteRegionCaptureLight(taskSettings); + // case RegionCaptureType.Transparent: + // return ExecuteRegionCaptureTransparent(taskSettings); + // } + // } protected TaskMetadata ExecuteRegionCapture(TaskSettings taskSettings) { @@ -140,5 +132,10 @@ protected TaskMetadata ExecuteRegionCaptureTransparent(TaskSettings taskSettings return null; } + + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + throw new NotImplementedException(); + } } diff --git a/SnapX.Core/SharpCapture/CaptureWindow.cs b/SnapX.Core/SharpCapture/CaptureWindow.cs new file mode 100644 index 000000000..ea4a89a14 --- /dev/null +++ b/SnapX.Core/SharpCapture/CaptureWindow.cs @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + + +using SnapX.Core.Interfaces; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; + +namespace SnapX.Core.SharpCapture; +public class CaptureWindow(IMainWindowService MainWindowService, INotificationService NotificationService, IUploadManager UploadManager, IDelayService DelayService, ILoggerService LoggerService, ICaptureService CaptureService, IntPtr? WindowHandle = 0) : CaptureBase(MainWindowService, NotificationService, UploadManager, DelayService, LoggerService, CaptureService) +{ + public IntPtr WindowHandle { get; protected set; } = WindowHandle.GetValueOrDefault(IntPtr.Zero); + + // protected override TaskMetadata Execute(TaskSettings? taskSettings) + // { + // WindowInfo windowInfo = new(WindowHandle); + // + // if (windowInfo.IsMinimized) + // { + // windowInfo.Restore(); + // Thread.Sleep(250); + // } + // + // if (!windowInfo.IsActive) + // { + // windowInfo.Activate(); + // Thread.Sleep(100); + // } + // + // var metadata = new TaskMetadata(); + // metadata.UpdateInfo(windowInfo); + // + // if (taskSettings.CaptureSettings.CaptureTransparent && !taskSettings.CaptureSettings.CaptureClientArea) + // { + // metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureWindowTransparent(WindowHandle); + // } + // else + // { + // metadata.Image = TaskHelpers.GetScreenshot(taskSettings).CaptureWindow(WindowHandle); + // } + // + // return metadata; + // } + protected override async Task ExecuteAsync(TaskSettings taskSettings) + { + throw new NotImplementedException(); + } +} + diff --git a/SnapX.Core/ScreenCapture/Enums.cs b/SnapX.Core/SharpCapture/Enums.cs similarity index 99% rename from SnapX.Core/ScreenCapture/Enums.cs rename to SnapX.Core/SharpCapture/Enums.cs index 4ea2ad274..17863fa7a 100644 --- a/SnapX.Core/ScreenCapture/Enums.cs +++ b/SnapX.Core/SharpCapture/Enums.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.ComponentModel; -namespace SnapX.Core.ScreenCapture; +namespace SnapX.Core.SharpCapture; public enum ScreenRecordOutput { diff --git a/SnapX.Core/ScreenCapture/Helpers/InputManager.cs b/SnapX.Core/SharpCapture/Helpers/InputManager.cs similarity index 93% rename from SnapX.Core/ScreenCapture/Helpers/InputManager.cs rename to SnapX.Core/SharpCapture/Helpers/InputManager.cs index 4d6bb8917..4a7eccf4c 100644 --- a/SnapX.Core/ScreenCapture/Helpers/InputManager.cs +++ b/SnapX.Core/SharpCapture/Helpers/InputManager.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; -namespace SnapX.Core.ScreenCapture.Helpers; +namespace SnapX.Core.SharpCapture.Helpers; public class InputManager { diff --git a/SnapX.Core/ScreenCapture/Helpers/LocationInfo.cs b/SnapX.Core/SharpCapture/Helpers/LocationInfo.cs similarity index 86% rename from SnapX.Core/ScreenCapture/Helpers/LocationInfo.cs rename to SnapX.Core/SharpCapture/Helpers/LocationInfo.cs index 89a19a93b..cb18921bd 100644 --- a/SnapX.Core/ScreenCapture/Helpers/LocationInfo.cs +++ b/SnapX.Core/SharpCapture/Helpers/LocationInfo.cs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -namespace SnapX.Core.ScreenCapture.Helpers; +namespace SnapX.Core.SharpCapture.Helpers; public class LocationInfo diff --git a/SnapX.Core/ScreenCapture/Helpers/SimpleWindowInfo.cs b/SnapX.Core/SharpCapture/Helpers/SimpleWindowInfo.cs similarity index 92% rename from SnapX.Core/ScreenCapture/Helpers/SimpleWindowInfo.cs rename to SnapX.Core/SharpCapture/Helpers/SimpleWindowInfo.cs index 2a3ef5ec5..937d3aa27 100644 --- a/SnapX.Core/ScreenCapture/Helpers/SimpleWindowInfo.cs +++ b/SnapX.Core/SharpCapture/Helpers/SimpleWindowInfo.cs @@ -1,11 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; using SnapX.Core.Media; -namespace SnapX.Core.ScreenCapture.Helpers; +namespace SnapX.Core.SharpCapture.Helpers; public class SimpleWindowInfo diff --git a/SnapX.Core/ScreenCapture/Helpers/SnapSize.cs b/SnapX.Core/SharpCapture/Helpers/SnapSize.cs similarity index 95% rename from SnapX.Core/ScreenCapture/Helpers/SnapSize.cs rename to SnapX.Core/SharpCapture/Helpers/SnapSize.cs index d7de82598..277e662b2 100644 --- a/SnapX.Core/ScreenCapture/Helpers/SnapSize.cs +++ b/SnapX.Core/SharpCapture/Helpers/SnapSize.cs @@ -1,10 +1,9 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Drawing; -namespace SnapX.Core.ScreenCapture.Helpers; +namespace SnapX.Core.SharpCapture.Helpers; public class SnapSize { diff --git a/SnapX.Core/ScreenCapture/Helpers/WindowsList.cs b/SnapX.Core/SharpCapture/Helpers/WindowsList.cs similarity index 96% rename from SnapX.Core/ScreenCapture/Helpers/WindowsList.cs rename to SnapX.Core/SharpCapture/Helpers/WindowsList.cs index 1f3c37b87..31e8eaf2c 100644 --- a/SnapX.Core/ScreenCapture/Helpers/WindowsList.cs +++ b/SnapX.Core/SharpCapture/Helpers/WindowsList.cs @@ -4,7 +4,7 @@ using SnapX.Core.Utils.Extensions; using SnapX.Core.Utils.Native; -namespace SnapX.Core.ScreenCapture.Helpers; +namespace SnapX.Core.SharpCapture.Helpers; public class WindowsList { diff --git a/SnapX.Core/SharpCapture/Interfaces/ICaptureService.cs b/SnapX.Core/SharpCapture/Interfaces/ICaptureService.cs new file mode 100644 index 000000000..f32c6d0bb --- /dev/null +++ b/SnapX.Core/SharpCapture/Interfaces/ICaptureService.cs @@ -0,0 +1,12 @@ +using SixLabors.ImageSharp; +using SnapX.Core.Job; + +namespace SnapX.Core.SharpCapture.Interfaces; + +public interface ICaptureService +{ + Task CaptureActiveMonitorAsync(TaskSettings? taskSettings = null); + Task CaptureFullscreenAsync(TaskSettings? taskSettings = null); + Task CaptureRectangle(TaskSettings? taskSettings = null, Rectangle? rect = null); + Task CaptureActiveWindowAsync(TaskSettings? taskSettings = null); +} diff --git a/SnapX.Core/SharpCapture/Linux/DBus/DesktopDBus.cs b/SnapX.Core/SharpCapture/Linux/DBus/DesktopDBus.cs index 62a78f26c..5a0e40ee5 100644 --- a/SnapX.Core/SharpCapture/Linux/DBus/DesktopDBus.cs +++ b/SnapX.Core/SharpCapture/Linux/DBus/DesktopDBus.cs @@ -5,127 +5,6 @@ namespace SnapX.Core.SharpCapture.Linux.DBus; -record InhibitProperties -{ - public uint Version { get; set; } = default!; -} -partial class Inhibit : DesktopObject -{ - private const string __Interface = "org.freedesktop.portal.Inhibit"; - public Inhibit(DesktopService service, ObjectPath path) : base(service, path) - { } - public Task InhibitAsync(string window, uint flags, Dictionary options) - { - return this.Connection.CallMethodAsync(CreateMessage(), (Message m, object? s) => ReadMessage_o(m, (DesktopObject)s!), this); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "sua{sv}", - member: "Inhibit"); - writer.WriteString(window); - writer.WriteUInt32(flags); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - public Task CreateMonitorAsync(string window, Dictionary options) - { - return this.Connection.CallMethodAsync(CreateMessage(), (Message m, object? s) => ReadMessage_o(m, (DesktopObject)s!), this); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "sa{sv}", - member: "CreateMonitor"); - writer.WriteString(window); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - public Task QueryEndResponseAsync(ObjectPath sessionHandle) - { - return this.Connection.CallMethodAsync(CreateMessage()); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "o", - member: "QueryEndResponse"); - writer.WriteObjectPath(sessionHandle); - return writer.CreateMessage(); - } - } - public ValueTask WatchStateChangedAsync(Action State)> handler, bool emitOnCapturedContext = true, ObserverFlags flags = ObserverFlags.None) - => base.WatchSignalAsync(Service.Destination, __Interface, Path, "StateChanged", (Message m, object? s) => ReadMessage_oaesv(m, (DesktopObject)s!), handler, emitOnCapturedContext, flags); - public Task GetVersionAsync() - => this.Connection.CallMethodAsync(CreateGetPropertyMessage(__Interface, "version"), (Message m, object? s) => ReadMessage_v_u(m, (DesktopObject)s!), this); - public Task GetPropertiesAsync() - { - return this.Connection.CallMethodAsync(CreateGetAllPropertiesMessage(__Interface), (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), this); - static InhibitProperties ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true, ObserverFlags flags = ObserverFlags.None) - { - return base.WatchPropertiesChangedAsync(__Interface, (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), handler, emitOnCapturedContext, flags); - static PropertyChanges ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(), invalidated = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), ReadInvalidated(ref reader), changed.ToArray()); - } - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(arrayEnd)) - { - invalidated ??= new(); - var property = reader.ReadString(); - switch (property) - { - case "version": invalidated.Add("Version"); break; - } - } - return invalidated?.ToArray() ?? Array.Empty(); - } - } - private static InhibitProperties ReadProperties(ref Reader reader, List? changedList = null) - { - var props = new InhibitProperties(); - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(arrayEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"u8); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariantValue(); - break; - } - } - return props; - } -} record BackgroundProperties { public uint Version { get; set; } = default!; @@ -227,110 +106,6 @@ private static BackgroundProperties ReadProperties(ref Reader reader, List CreateSessionAsync(Dictionary options) - { - return this.Connection.CallMethodAsync(CreateMessage(), (Message m, object? s) => ReadMessage_o(m, (DesktopObject)s!), this); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "a{sv}", - member: "CreateSession"); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - public Task StartAsync(ObjectPath sessionHandle, string parentWindow, Dictionary options) - { - return this.Connection.CallMethodAsync(CreateMessage(), (Message m, object? s) => ReadMessage_o(m, (DesktopObject)s!), this); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "osa{sv}", - member: "Start"); - writer.WriteObjectPath(sessionHandle); - writer.WriteString(parentWindow); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - public ValueTask WatchLocationUpdatedAsync(Action Location)> handler, bool emitOnCapturedContext = true, ObserverFlags flags = ObserverFlags.None) - => base.WatchSignalAsync(Service.Destination, __Interface, Path, "LocationUpdated", (Message m, object? s) => ReadMessage_oaesv(m, (DesktopObject)s!), handler, emitOnCapturedContext, flags); - public Task GetVersionAsync() - => this.Connection.CallMethodAsync(CreateGetPropertyMessage(__Interface, "version"), (Message m, object? s) => ReadMessage_v_u(m, (DesktopObject)s!), this); - public Task GetPropertiesAsync() - { - return this.Connection.CallMethodAsync(CreateGetAllPropertiesMessage(__Interface), (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), this); - static LocationProperties ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true, ObserverFlags flags = ObserverFlags.None) - { - return base.WatchPropertiesChangedAsync(__Interface, (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), handler, emitOnCapturedContext, flags); - static PropertyChanges ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(), invalidated = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), ReadInvalidated(ref reader), changed.ToArray()); - } - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(arrayEnd)) - { - invalidated ??= new(); - var property = reader.ReadString(); - switch (property) - { - case "version": invalidated.Add("Version"); break; - } - } - return invalidated?.ToArray() ?? Array.Empty(); - } - } - private static LocationProperties ReadProperties(ref Reader reader, List? changedList = null) - { - var props = new LocationProperties(); - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(arrayEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"u8); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariantValue(); - break; - } - } - return props; - } -} record NotificationProperties { public Dictionary SupportedOptions { get; set; } = default!; @@ -2862,91 +2637,6 @@ private static ScreenCastProperties ReadProperties(ref Reader reader, List ComposeEmailAsync(string parentWindow, Dictionary options) - { - return this.Connection.CallMethodAsync(CreateMessage(), (Message m, object? s) => ReadMessage_o(m, (DesktopObject)s!), this); - MessageBuffer CreateMessage() - { - var writer = this.Connection.GetMessageWriter(); - writer.WriteMethodCallHeader( - destination: Service.Destination, - path: Path, - @interface: __Interface, - signature: "sa{sv}", - member: "ComposeEmail"); - writer.WriteString(parentWindow); - writer.WriteDictionary(options); - return writer.CreateMessage(); - } - } - public Task GetVersionAsync() - => this.Connection.CallMethodAsync(CreateGetPropertyMessage(__Interface, "version"), (Message m, object? s) => ReadMessage_v_u(m, (DesktopObject)s!), this); - public Task GetPropertiesAsync() - { - return this.Connection.CallMethodAsync(CreateGetAllPropertiesMessage(__Interface), (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), this); - static EmailProperties ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - return ReadProperties(ref reader); - } - } - public ValueTask WatchPropertiesChangedAsync(Action> handler, bool emitOnCapturedContext = true, ObserverFlags flags = ObserverFlags.None) - { - return base.WatchPropertiesChangedAsync(__Interface, (Message m, object? s) => ReadMessage(m, (DesktopObject)s!), handler, emitOnCapturedContext, flags); - static PropertyChanges ReadMessage(Message message, DesktopObject _) - { - var reader = message.GetBodyReader(); - reader.ReadString(); // interface - List changed = new(), invalidated = new(); - return new PropertyChanges(ReadProperties(ref reader, changed), ReadInvalidated(ref reader), changed.ToArray()); - } - static string[] ReadInvalidated(ref Reader reader) - { - List? invalidated = null; - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.String); - while (reader.HasNext(arrayEnd)) - { - invalidated ??= new(); - var property = reader.ReadString(); - switch (property) - { - case "version": invalidated.Add("Version"); break; - } - } - return invalidated?.ToArray() ?? Array.Empty(); - } - } - private static EmailProperties ReadProperties(ref Reader reader, List? changedList = null) - { - var props = new EmailProperties(); - ArrayEnd arrayEnd = reader.ReadArrayStart(DBusType.Struct); - while (reader.HasNext(arrayEnd)) - { - var property = reader.ReadString(); - switch (property) - { - case "version": - reader.ReadSignature("u"u8); - props.Version = reader.ReadUInt32(); - changedList?.Add("Version"); - break; - default: - reader.ReadVariantValue(); - break; - } - } - return props; - } -} record TrashProperties { public uint Version { get; set; } = default!; @@ -3327,30 +3017,14 @@ partial class DesktopService public string Destination { get; } public DesktopService(Tmds.DBus.Protocol.Connection connection, string destination) => (Connection, Destination) = (connection, destination); - public Inhibit CreateInhibit(ObjectPath path) => new Inhibit(this, path); - public Background CreateBackground(ObjectPath path) => new Background(this, path); - public Location CreateLocation(ObjectPath path) => new Location(this, path); public Notification CreateNotification(ObjectPath path) => new Notification(this, path); public Screenshot CreateScreenshot(ObjectPath path) => new Screenshot(this, path); - public Account CreateAccount(ObjectPath path) => new Account(this, path); - public NetworkMonitor CreateNetworkMonitor(ObjectPath path) => new NetworkMonitor(this, path); - public Print CreatePrint(ObjectPath path) => new Print(this, path); - public Settings CreateSettings(ObjectPath path) => new Settings(this, path); - public GameMode CreateGameMode(ObjectPath path) => new GameMode(this, path); - public RemoteDesktop CreateRemoteDesktop(ObjectPath path) => new RemoteDesktop(this, path); - public MemoryMonitor CreateMemoryMonitor(ObjectPath path) => new MemoryMonitor(this, path); public OpenURI CreateOpenURI(ObjectPath path) => new OpenURI(this, path); public Realtime CreateRealtime(ObjectPath path) => new Realtime(this, path); public Secret CreateSecret(ObjectPath path) => new Secret(this, path); - public Camera CreateCamera(ObjectPath path) => new Camera(this, path); public InputCapture CreateInputCapture(ObjectPath path) => new InputCapture(this, path); public GlobalShortcuts CreateGlobalShortcuts(ObjectPath path) => new GlobalShortcuts(this, path); - public PowerProfileMonitor CreatePowerProfileMonitor(ObjectPath path) => new PowerProfileMonitor(this, path); - public DynamicLauncher CreateDynamicLauncher(ObjectPath path) => new DynamicLauncher(this, path); public ScreenCast CreateScreenCast(ObjectPath path) => new ScreenCast(this, path); - public Email CreateEmail(ObjectPath path) => new Email(this, path); - public Trash CreateTrash(ObjectPath path) => new Trash(this, path); - public ProxyResolver CreateProxyResolver(ObjectPath path) => new ProxyResolver(this, path); public FileChooser CreateFileChooser(ObjectPath path) => new FileChooser(this, path); public Session CreateSession(ObjectPath path) => new Session(this, path); } diff --git a/SnapX.Core/SharpCapture/Linux/DBus/PropertyChanges.cs b/SnapX.Core/SharpCapture/Linux/DBus/PropertyChanges.cs index ed73bd2d4..6fe1861be 100644 --- a/SnapX.Core/SharpCapture/Linux/DBus/PropertyChanges.cs +++ b/SnapX.Core/SharpCapture/Linux/DBus/PropertyChanges.cs @@ -1,12 +1,10 @@ namespace SnapX.Core.SharpCapture.Linux.DBus; -public class PropertyChanges +public class PropertyChanges(TProperties Properties, string[] Invalidated, string[] Changed) { - public PropertyChanges(TProperties properties, string[] invalidated, string[] changed) - => (Properties, Invalidated, Changed) = (properties, invalidated, changed); - public TProperties Properties { get; } - public string[] Invalidated { get; } - public string[] Changed { get; } + public TProperties Properties { get; } = Properties; + public string[] Invalidated { get; } = Invalidated; + public string[] Changed { get; } = Changed; public bool HasChanged(string property) => Array.IndexOf(Changed, property) != -1; public bool IsInvalidated(string property) => Array.IndexOf(Invalidated, property) != -1; } diff --git a/SnapX.Core/SharpCapture/Linux/LinuxCapture.cs b/SnapX.Core/SharpCapture/Linux/LinuxCapture.cs index c9ec1da04..65fe2915c 100644 --- a/SnapX.Core/SharpCapture/Linux/LinuxCapture.cs +++ b/SnapX.Core/SharpCapture/Linux/LinuxCapture.cs @@ -1,5 +1,6 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; +using SnapX.Core.Job; using SnapX.Core.SharpCapture.Linux.DBus; using SnapX.Core.Utils.Native; using Tmds.DBus; @@ -7,15 +8,15 @@ namespace SnapX.Core.SharpCapture.Linux; -public class LinuxCapture : BaseCapture +public class LinuxCapture : BaseSharpCapture { - public override async Task CaptureFullscreen() + public override async Task CaptureFullscreen(TaskSettings? taskSettings = null) { if (LinuxAPI.IsWayland() && !IsCompositorKwin) return await TakeScreenshotWithPortal(); var screen = Methods.GetScreen(Methods.GetCursorPosition()); if (!IsCompositorKwin) { - return LinuxAPI.TakeScreenshotWithX11(screen); + return ((LinuxAPI)Methods.NativeAPI).TakeScreenshotWithX11(screen); } // Todo: replace try catch with method that checks for valid kwin permissions. @@ -122,7 +123,7 @@ private static Image CropFullscreenScreenshotToBounds(Rectangle bounds, Image im return img; } - public override async Task CaptureScreen(Rectangle bounds) + public override async Task CaptureScreen(Rectangle bounds, TaskSettings? taskSettings = null) { var fullscreenImage = await CaptureFullscreen().ConfigureAwait(false); var croppedImage = CropFullscreenScreenshotToBounds(bounds, fullscreenImage); @@ -132,7 +133,7 @@ private static Image CropFullscreenScreenshotToBounds(Rectangle bounds, Image im // return LinuxAPI.TakeScreenshotWithX11(screen); } - public override async Task CaptureScreen(Point? pos) + public override async Task CaptureScreen(Point? pos, TaskSettings? taskSettings = null) { if (pos == null || !pos.HasValue) throw new ArgumentNullException(nameof(pos)); return await CaptureScreen(await GetScreen(pos.Value)); @@ -141,7 +142,7 @@ private static Image CropFullscreenScreenshotToBounds(Rectangle bounds, Image im public override async Task GetScreen(Point pos) => Methods.NativeAPI.GetScreen(pos).Bounds; public override async Task GetWorkingArea() => ((LinuxAPI)Methods.NativeAPI).GetScreenBounds(); - public override async Task CaptureRectangle(Rectangle rect) + public override async Task CaptureRectangle(Rectangle rect, TaskSettings? taskSettings = null) { return CropFullscreenScreenshotToBounds(rect, await CaptureFullscreen().ConfigureAwait(false)); } diff --git a/SnapX.Core/ScreenCapture/RegionCaptureOptions.cs b/SnapX.Core/SharpCapture/RegionCaptureOptions.cs similarity index 87% rename from SnapX.Core/ScreenCapture/RegionCaptureOptions.cs rename to SnapX.Core/SharpCapture/RegionCaptureOptions.cs index 4a2a7eac4..01588b564 100644 --- a/SnapX.Core/ScreenCapture/RegionCaptureOptions.cs +++ b/SnapX.Core/SharpCapture/RegionCaptureOptions.cs @@ -1,12 +1,12 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; +using SnapX.Core.History; using SnapX.Core.ImageEffects; -using SnapX.Core.ScreenCapture.Helpers; +using SnapX.Core.SharpCapture.Helpers; -namespace SnapX.Core.ScreenCapture; +namespace SnapX.Core.SharpCapture; public class RegionCaptureOptions { @@ -34,16 +34,20 @@ public class RegionCaptureOptions public string CustomInfoText = "X: $x, Y: $y$nR: $r, G: $g, B: $b$nHex: $hex"; // Formats: $x, $y, $r, $g, $b, $hex, $HEX, $n public List SnapSizes = [ - new(426, 240), // 240p - new(640, 360), // 360p - new(854, 480), // 480p - new(1280, 720), // 720p - new(1920, 1080) // 1080p + new(426, 240), // 240p + new(640, 360), // 360p + new(854, 480), // 480p + new(1280, 720), // 720p + new(1920, 1080), // 1080p + new(2560, 1440), // 1440p + new(3840, 2160), // 2160p + new(5120, 2880), // 2880p / 5K + new(7680, 4320) // 4320p / 8K ]; public bool ShowInfo = true; public bool ShowMagnifier = true; public bool UseSquareMagnifier = false; - public int MagnifierPixelCount = 15; // Must be odd number like 11, 13, 15 etc. + public int MagnifierPixelCount = 15; // Must be odd number like 11, 13, 15, etc. public int MagnifierPixelSize = 10; public bool ShowCrosshair = false; public bool UseLightResizeNodes = false; @@ -76,7 +80,7 @@ public class RegionCaptureOptions public bool AutoCloseEditorOnTask = false; public bool ShowEditorPanTip = true; public ImageInterpolationMode ImageEditorResizeInterpolationMode = ImageInterpolationMode.Bicubic; - public Size EditorNewImageSize = new Size(800, 600); + public Size EditorNewImageSize = new(800, 600); public bool EditorNewImageTransparent = false; public Color EditorNewImageBackgroundColor = Color.White; public Color EditorCanvasColor = Color.Transparent; diff --git a/SnapX.Core/ScreenCapture/RegionCaptureTasks.cs b/SnapX.Core/SharpCapture/RegionCaptureTasks.cs similarity index 98% rename from SnapX.Core/ScreenCapture/RegionCaptureTasks.cs rename to SnapX.Core/SharpCapture/RegionCaptureTasks.cs index 7d454c48d..0569accd5 100644 --- a/SnapX.Core/ScreenCapture/RegionCaptureTasks.cs +++ b/SnapX.Core/SharpCapture/RegionCaptureTasks.cs @@ -4,9 +4,9 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SnapX.Core.Media; -using SnapX.Core.ScreenCapture.Helpers; +using SnapX.Core.SharpCapture.Helpers; -namespace SnapX.Core.ScreenCapture; +namespace SnapX.Core.SharpCapture; public static class RegionCaptureTasks { diff --git a/SnapX.Core/ScreenCapture/Rust/Cargo.lock b/SnapX.Core/SharpCapture/Rust/Cargo.lock similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/Cargo.lock rename to SnapX.Core/SharpCapture/Rust/Cargo.lock diff --git a/SnapX.Core/ScreenCapture/Rust/Cargo.toml b/SnapX.Core/SharpCapture/Rust/Cargo.toml similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/Cargo.toml rename to SnapX.Core/SharpCapture/Rust/Cargo.toml diff --git a/SnapX.Core/ScreenCapture/Rust/bindings/snapxrust.cs b/SnapX.Core/SharpCapture/Rust/bindings/snapxrust.cs similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/bindings/snapxrust.cs rename to SnapX.Core/SharpCapture/Rust/bindings/snapxrust.cs diff --git a/SnapX.Core/SharpCapture/Rust/bindings/snapxrust.py b/SnapX.Core/SharpCapture/Rust/bindings/snapxrust.py new file mode 100644 index 000000000..a8186a831 --- /dev/null +++ b/SnapX.Core/SharpCapture/Rust/bindings/snapxrust.py @@ -0,0 +1,1090 @@ +# This file was autogenerated by some hot garbage in the `uniffi` crate. +# Trust me, you don't want to mess with it! + +# Common helper code. +# +# Ideally this would live in a separate .py file where it can be unittested etc +# in isolation, and perhaps even published as a re-useable package. +# +# However, it's important that the details of how this helper code works (e.g. the +# way that different builtin types are passed across the FFI) exactly match what's +# expected by the rust code on the other side of the interface. In practice right +# now that means coming from the exact some version of `uniffi` that was used to +# compile the rust component. The easiest way to ensure this is to bundle the Python +# helpers directly inline like we're doing here. + +import os +import sys +import ctypes +import enum +import struct +import contextlib +import datetime +import typing +import platform + +# Used for default argument values +_DEFAULT = object() + + +class _UniffiRustBuffer(ctypes.Structure): + _fields_ = [ + ("capacity", ctypes.c_int32), + ("len", ctypes.c_int32), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + @staticmethod + def alloc(size): + return _rust_call(_UniffiLib.ffi_snapxrust_rustbuffer_alloc, size) + + @staticmethod + def reserve(rbuf, additional): + return _rust_call(_UniffiLib.ffi_snapxrust_rustbuffer_reserve, rbuf, additional) + + def free(self): + return _rust_call(_UniffiLib.ffi_snapxrust_rustbuffer_free, self) + + def __str__(self): + return "_UniffiRustBuffer(capacity={}, len={}, data={})".format( + self.capacity, + self.len, + self.data[0:self.len] + ) + + @contextlib.contextmanager + def alloc_with_builder(*args): + """Context-manger to allocate a buffer using a _UniffiRustBufferBuilder. + + The allocated buffer will be automatically freed if an error occurs, ensuring that + we don't accidentally leak it. + """ + builder = _UniffiRustBufferBuilder() + try: + yield builder + except: + builder.discard() + raise + + @contextlib.contextmanager + def consume_with_stream(self): + """Context-manager to consume a buffer using a _UniffiRustBufferStream. + + The _UniffiRustBuffer will be freed once the context-manager exits, ensuring that we don't + leak it even if an error occurs. + """ + try: + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of consume_with_stream") + finally: + self.free() + + @contextlib.contextmanager + def read_with_stream(self): + """Context-manager to read a buffer using a _UniffiRustBufferStream. + + This is like consume_with_stream, but doesn't free the buffer afterwards. + It should only be used with borrowed `_UniffiRustBuffer` data. + """ + s = _UniffiRustBufferStream.from_rust_buffer(self) + yield s + if s.remaining() != 0: + raise RuntimeError("junk data left in buffer at end of read_with_stream") + +class _UniffiForeignBytes(ctypes.Structure): + _fields_ = [ + ("len", ctypes.c_int32), + ("data", ctypes.POINTER(ctypes.c_char)), + ] + + def __str__(self): + return "_UniffiForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len]) + + +class _UniffiRustBufferStream: + """ + Helper for structured reading of bytes from a _UniffiRustBuffer + """ + + def __init__(self, data, len): + self.data = data + self.len = len + self.offset = 0 + + @classmethod + def from_rust_buffer(cls, buf): + return cls(buf.data, buf.len) + + def remaining(self): + return self.len - self.offset + + def _unpack_from(self, size, format): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + value = struct.unpack(format, self.data[self.offset:self.offset+size])[0] + self.offset += size + return value + + def read(self, size): + if self.offset + size > self.len: + raise InternalError("read past end of rust buffer") + data = self.data[self.offset:self.offset+size] + self.offset += size + return data + + def read_i8(self): + return self._unpack_from(1, ">b") + + def read_u8(self): + return self._unpack_from(1, ">B") + + def read_i16(self): + return self._unpack_from(2, ">h") + + def read_u16(self): + return self._unpack_from(2, ">H") + + def read_i32(self): + return self._unpack_from(4, ">i") + + def read_u32(self): + return self._unpack_from(4, ">I") + + def read_i64(self): + return self._unpack_from(8, ">q") + + def read_u64(self): + return self._unpack_from(8, ">Q") + + def read_float(self): + v = self._unpack_from(4, ">f") + return v + + def read_double(self): + return self._unpack_from(8, ">d") + + def read_c_size_t(self): + return self._unpack_from(ctypes.sizeof(ctypes.c_size_t) , "@N") + +class _UniffiRustBufferBuilder: + """ + Helper for structured writing of bytes into a _UniffiRustBuffer. + """ + + def __init__(self): + self.rbuf = _UniffiRustBuffer.alloc(16) + self.rbuf.len = 0 + + def finalize(self): + rbuf = self.rbuf + self.rbuf = None + return rbuf + + def discard(self): + if self.rbuf is not None: + rbuf = self.finalize() + rbuf.free() + + @contextlib.contextmanager + def _reserve(self, num_bytes): + if self.rbuf.len + num_bytes > self.rbuf.capacity: + self.rbuf = _UniffiRustBuffer.reserve(self.rbuf, num_bytes) + yield None + self.rbuf.len += num_bytes + + def _pack_into(self, size, format, value): + with self._reserve(size): + # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out. + for i, byte in enumerate(struct.pack(format, value)): + self.rbuf.data[self.rbuf.len + i] = byte + + def write(self, value): + with self._reserve(len(value)): + for i, byte in enumerate(value): + self.rbuf.data[self.rbuf.len + i] = byte + + def write_i8(self, v): + self._pack_into(1, ">b", v) + + def write_u8(self, v): + self._pack_into(1, ">B", v) + + def write_i16(self, v): + self._pack_into(2, ">h", v) + + def write_u16(self, v): + self._pack_into(2, ">H", v) + + def write_i32(self, v): + self._pack_into(4, ">i", v) + + def write_u32(self, v): + self._pack_into(4, ">I", v) + + def write_i64(self, v): + self._pack_into(8, ">q", v) + + def write_u64(self, v): + self._pack_into(8, ">Q", v) + + def write_float(self, v): + self._pack_into(4, ">f", v) + + def write_double(self, v): + self._pack_into(8, ">d", v) + + def write_c_size_t(self, v): + self._pack_into(ctypes.sizeof(ctypes.c_size_t) , "@N", v) +# A handful of classes and functions to support the generated data structures. +# This would be a good candidate for isolating in its own ffi-support lib. + +class InternalError(Exception): + pass + +class _UniffiRustCallStatus(ctypes.Structure): + """ + Error runtime. + """ + _fields_ = [ + ("code", ctypes.c_int8), + ("error_buf", _UniffiRustBuffer), + ] + + # These match the values from the uniffi::rustcalls module + CALL_SUCCESS = 0 + CALL_ERROR = 1 + CALL_PANIC = 2 + + def __str__(self): + if self.code == _UniffiRustCallStatus.CALL_SUCCESS: + return "_UniffiRustCallStatus(CALL_SUCCESS)" + elif self.code == _UniffiRustCallStatus.CALL_ERROR: + return "_UniffiRustCallStatus(CALL_ERROR)" + elif self.code == _UniffiRustCallStatus.CALL_PANIC: + return "_UniffiRustCallStatus(CALL_PANIC)" + else: + return "_UniffiRustCallStatus()" + +def _rust_call(fn, *args): + # Call a rust function + return _rust_call_with_error(None, fn, *args) + +def _rust_call_with_error(error_ffi_converter, fn, *args): + # Call a rust function and handle any errors + # + # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code. + # error_ffi_converter must be set to the _UniffiConverter for the error class that corresponds to the result. + call_status = _UniffiRustCallStatus(code=_UniffiRustCallStatus.CALL_SUCCESS, error_buf=_UniffiRustBuffer(0, 0, None)) + + args_with_error = args + (ctypes.byref(call_status),) + result = fn(*args_with_error) + _uniffi_check_call_status(error_ffi_converter, call_status) + return result + +def _uniffi_check_call_status(error_ffi_converter, call_status): + if call_status.code == _UniffiRustCallStatus.CALL_SUCCESS: + pass + elif call_status.code == _UniffiRustCallStatus.CALL_ERROR: + if error_ffi_converter is None: + call_status.error_buf.free() + raise InternalError("_rust_call_with_error: CALL_ERROR, but error_ffi_converter is None") + else: + raise error_ffi_converter.lift(call_status.error_buf) + elif call_status.code == _UniffiRustCallStatus.CALL_PANIC: + # When the rust code sees a panic, it tries to construct a _UniffiRustBuffer + # with the message. But if that code panics, then it just sends back + # an empty buffer. + if call_status.error_buf.len > 0: + msg = _UniffiConverterString.lift(call_status.error_buf) + else: + msg = "Unknown rust panic" + raise InternalError(msg) + else: + raise InternalError("Invalid _UniffiRustCallStatus code: {}".format( + call_status.code)) + +# A function pointer for a callback as defined by UniFFI. +# Rust definition `fn(handle: u64, method: u32, args: _UniffiRustBuffer, buf_ptr: *mut _UniffiRustBuffer) -> int` +_UNIFFI_FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_char), ctypes.c_int, ctypes.POINTER(_UniffiRustBuffer)) + +# UniFFI future continuation +_UNIFFI_FUTURE_CONTINUATION_T = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int8) + +class _UniffiPointerManagerCPython: + """ + Manage giving out pointers to Python objects on CPython + + This class is used to generate opaque pointers that reference Python objects to pass to Rust. + It assumes a CPython platform. See _UniffiPointerManagerGeneral for the alternative. + """ + + def new_pointer(self, obj): + """ + Get a pointer for an object as a ctypes.c_size_t instance + + Each call to new_pointer() must be balanced with exactly one call to release_pointer() + + This returns a ctypes.c_size_t. This is always the same size as a pointer and can be + interchanged with pointers for FFI function arguments and return values. + """ + # IncRef the object since we're going to pass a pointer to Rust + ctypes.pythonapi.Py_IncRef(ctypes.py_object(obj)) + # id() is the object address on CPython + # (https://docs.python.org/3/library/functions.html#id) + return id(obj) + + def release_pointer(self, address): + py_obj = ctypes.cast(address, ctypes.py_object) + obj = py_obj.value + ctypes.pythonapi.Py_DecRef(py_obj) + return obj + + def lookup(self, address): + return ctypes.cast(address, ctypes.py_object).value + +class _UniffiPointerManagerGeneral: + """ + Manage giving out pointers to Python objects on non-CPython platforms + + This has the same API as _UniffiPointerManagerCPython, but doesn't assume we're running on + CPython and is slightly slower. + + Instead of using real pointers, it maps integer values to objects and returns the keys as + c_size_t values. + """ + + def __init__(self): + self._map = {} + self._lock = threading.Lock() + self._current_handle = 0 + + def new_pointer(self, obj): + with self._lock: + handle = self._current_handle + self._current_handle += 1 + self._map[handle] = obj + return handle + + def release_pointer(self, handle): + with self._lock: + return self._map.pop(handle) + + def lookup(self, handle): + with self._lock: + return self._map[handle] + +# Pick an pointer manager implementation based on the platform +if platform.python_implementation() == 'CPython': + _UniffiPointerManager = _UniffiPointerManagerCPython # type: ignore +else: + _UniffiPointerManager = _UniffiPointerManagerGeneral # type: ignore +# Types conforming to `_UniffiConverterPrimitive` pass themselves directly over the FFI. +class _UniffiConverterPrimitive: + @classmethod + def check(cls, value): + return value + + @classmethod + def lift(cls, value): + return value + + @classmethod + def lower(cls, value): + return cls.lowerUnchecked(cls.check(value)) + + @classmethod + def lowerUnchecked(cls, value): + return value + + @classmethod + def write(cls, value, buf): + cls.write_unchecked(cls.check(value), buf) + +class _UniffiConverterPrimitiveInt(_UniffiConverterPrimitive): + @classmethod + def check(cls, value): + try: + value = value.__index__() + except Exception: + raise TypeError("'{}' object cannot be interpreted as an integer".format(type(value).__name__)) + if not isinstance(value, int): + raise TypeError("__index__ returned non-int (type {})".format(type(value).__name__)) + if not cls.VALUE_MIN <= value < cls.VALUE_MAX: + raise ValueError("{} requires {} <= value < {}".format(cls.CLASS_NAME, cls.VALUE_MIN, cls.VALUE_MAX)) + return super().check(value) + +class _UniffiConverterPrimitiveFloat(_UniffiConverterPrimitive): + @classmethod + def check(cls, value): + try: + value = value.__float__() + except Exception: + raise TypeError("must be real number, not {}".format(type(value).__name__)) + if not isinstance(value, float): + raise TypeError("__float__ returned non-float (type {})".format(type(value).__name__)) + return super().check(value) + +# Helper class for wrapper types that will always go through a _UniffiRustBuffer. +# Classes should inherit from this and implement the `read` and `write` static methods. +class _UniffiConverterRustBuffer: + @classmethod + def lift(cls, rbuf): + with rbuf.consume_with_stream() as stream: + return cls.read(stream) + + @classmethod + def lower(cls, value): + with _UniffiRustBuffer.alloc_with_builder() as builder: + cls.write(value, builder) + return builder.finalize() + +# Contains loading, initialization code, and the FFI Function declarations. +# Define some ctypes FFI types that we use in the library + +""" +ctypes type for the foreign executor callback. This is a built-in interface for scheduling +tasks + +Args: + executor: opaque c_size_t value representing the eventloop + delay: delay in ms + task: function pointer to the task callback + task_data: void pointer to the task callback data + +Normally we should call task(task_data) after the detail. +However, when task is NULL this indicates that Rust has dropped the ForeignExecutor and we should +decrease the EventLoop refcount. +""" +_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int8, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p) + +""" +Function pointer for a Rust task, which a callback function that takes a opaque pointer +""" +_UNIFFI_RUST_TASK = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_int8) + +def _uniffi_future_callback_t(return_type): + """ + Factory function to create callback function types for async functions + """ + return ctypes.CFUNCTYPE(None, ctypes.c_size_t, return_type, _UniffiRustCallStatus) + +def _uniffi_load_indirect(): + """ + This is how we find and load the dynamic library provided by the component. + For now we just look it up by name. + """ + if sys.platform == "darwin": + libname = "lib{}.dylib" + elif sys.platform.startswith("win"): + # As of python3.8, ctypes does not seem to search $PATH when loading DLLs. + # We could use `os.add_dll_directory` to configure the search path, but + # it doesn't feel right to mess with application-wide settings. Let's + # assume that the `.dll` is next to the `.py` file and load by full path. + libname = os.path.join( + os.path.dirname(__file__), + "{}.dll", + ) + else: + # Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos + libname = "lib{}.so" + + libname = libname.format("uniffi_snapxrust") + path = os.path.join(os.path.dirname(__file__), libname) + lib = ctypes.cdll.LoadLibrary(path) + return lib + +def _uniffi_check_contract_api_version(lib): + # Get the bindings contract version from our ComponentInterface + bindings_contract_version = 24 + # Get the scaffolding contract version by calling the into the dylib + scaffolding_contract_version = lib.ffi_snapxrust_uniffi_contract_version() + if bindings_contract_version != scaffolding_contract_version: + raise InternalError("UniFFI contract version mismatch: try cleaning and rebuilding your project") + +def _uniffi_check_api_checksums(lib): + if lib.uniffi_snapxrust_checksum_func_capture_fullscreen() != 6651: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_capture_monitor() != 61593: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_capture_rect() != 15851: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_capture_window() != 52724: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_get_monitor() != 61273: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_get_primary_monitor() != 12932: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_get_screen_dimensions() != 25884: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_snapxrust_checksum_func_get_working_area() != 60391: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + +# A ctypes library to expose the extern-C FFI definitions. +# This is an implementation detail which will be called internally by the public API. + +_UniffiLib = _uniffi_load_indirect() +_UniffiLib.uniffi_snapxrust_fn_func_capture_fullscreen.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_capture_fullscreen.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_capture_monitor.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_capture_monitor.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_capture_rect.argtypes = ( + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_capture_rect.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_capture_window.argtypes = ( + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_capture_window.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_get_monitor.argtypes = ( + ctypes.c_uint32, + ctypes.c_uint32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_get_monitor.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_get_primary_monitor.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_get_primary_monitor.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_get_screen_dimensions.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_get_screen_dimensions.restype = _UniffiRustBuffer +_UniffiLib.uniffi_snapxrust_fn_func_get_working_area.argtypes = ( + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_snapxrust_fn_func_get_working_area.restype = _UniffiRustBuffer +_UniffiLib.ffi_snapxrust_rustbuffer_alloc.argtypes = ( + ctypes.c_int32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rustbuffer_alloc.restype = _UniffiRustBuffer +_UniffiLib.ffi_snapxrust_rustbuffer_from_bytes.argtypes = ( + _UniffiForeignBytes, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rustbuffer_from_bytes.restype = _UniffiRustBuffer +_UniffiLib.ffi_snapxrust_rustbuffer_free.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rustbuffer_free.restype = None +_UniffiLib.ffi_snapxrust_rustbuffer_reserve.argtypes = ( + _UniffiRustBuffer, + ctypes.c_int32, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rustbuffer_reserve.restype = _UniffiRustBuffer +_UniffiLib.ffi_snapxrust_rust_future_continuation_callback_set.argtypes = ( + _UNIFFI_FUTURE_CONTINUATION_T, +) +_UniffiLib.ffi_snapxrust_rust_future_continuation_callback_set.restype = None +_UniffiLib.ffi_snapxrust_rust_future_poll_u8.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_u8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_u8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_u8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_u8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_u8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_u8.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_u8.restype = ctypes.c_uint8 +_UniffiLib.ffi_snapxrust_rust_future_poll_i8.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_i8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_i8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_i8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_i8.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_i8.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_i8.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_i8.restype = ctypes.c_int8 +_UniffiLib.ffi_snapxrust_rust_future_poll_u16.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_u16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_u16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_u16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_u16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_u16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_u16.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_u16.restype = ctypes.c_uint16 +_UniffiLib.ffi_snapxrust_rust_future_poll_i16.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_i16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_i16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_i16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_i16.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_i16.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_i16.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_i16.restype = ctypes.c_int16 +_UniffiLib.ffi_snapxrust_rust_future_poll_u32.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_u32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_u32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_u32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_u32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_u32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_u32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_u32.restype = ctypes.c_uint32 +_UniffiLib.ffi_snapxrust_rust_future_poll_i32.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_i32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_i32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_i32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_i32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_i32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_i32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_i32.restype = ctypes.c_int32 +_UniffiLib.ffi_snapxrust_rust_future_poll_u64.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_u64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_u64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_u64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_u64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_u64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_u64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_u64.restype = ctypes.c_uint64 +_UniffiLib.ffi_snapxrust_rust_future_poll_i64.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_i64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_i64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_i64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_i64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_i64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_i64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_i64.restype = ctypes.c_int64 +_UniffiLib.ffi_snapxrust_rust_future_poll_f32.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_f32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_f32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_f32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_f32.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_f32.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_f32.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_f32.restype = ctypes.c_float +_UniffiLib.ffi_snapxrust_rust_future_poll_f64.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_f64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_f64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_f64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_f64.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_f64.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_f64.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_f64.restype = ctypes.c_double +_UniffiLib.ffi_snapxrust_rust_future_poll_pointer.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_pointer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_pointer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_pointer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_pointer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_pointer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_pointer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_pointer.restype = ctypes.c_void_p +_UniffiLib.ffi_snapxrust_rust_future_poll_rust_buffer.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_rust_buffer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_rust_buffer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_rust_buffer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_rust_buffer.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_rust_buffer.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_rust_buffer.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_rust_buffer.restype = _UniffiRustBuffer +_UniffiLib.ffi_snapxrust_rust_future_poll_void.argtypes = ( + ctypes.c_void_p, + ctypes.c_size_t, +) +_UniffiLib.ffi_snapxrust_rust_future_poll_void.restype = None +_UniffiLib.ffi_snapxrust_rust_future_cancel_void.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_cancel_void.restype = None +_UniffiLib.ffi_snapxrust_rust_future_free_void.argtypes = ( + ctypes.c_void_p, +) +_UniffiLib.ffi_snapxrust_rust_future_free_void.restype = None +_UniffiLib.ffi_snapxrust_rust_future_complete_void.argtypes = ( + ctypes.c_void_p, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.ffi_snapxrust_rust_future_complete_void.restype = None +_UniffiLib.uniffi_snapxrust_checksum_func_capture_fullscreen.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_capture_fullscreen.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_capture_monitor.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_capture_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_capture_rect.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_capture_rect.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_capture_window.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_capture_window.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_get_monitor.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_get_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_get_primary_monitor.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_get_primary_monitor.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_get_screen_dimensions.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_get_screen_dimensions.restype = ctypes.c_uint16 +_UniffiLib.uniffi_snapxrust_checksum_func_get_working_area.argtypes = ( +) +_UniffiLib.uniffi_snapxrust_checksum_func_get_working_area.restype = ctypes.c_uint16 +_UniffiLib.ffi_snapxrust_uniffi_contract_version.argtypes = ( +) +_UniffiLib.ffi_snapxrust_uniffi_contract_version.restype = ctypes.c_uint32 +_uniffi_check_contract_api_version(_UniffiLib) +_uniffi_check_api_checksums(_UniffiLib) + +# Async support + +# Public interface members begin here. + + +class _UniffiConverterUInt32(_UniffiConverterPrimitiveInt): + CLASS_NAME = "u32" + VALUE_MIN = 0 + VALUE_MAX = 2**32 + + @staticmethod + def read(buf): + return buf.read_u32() + + @staticmethod + def write_unchecked(value, buf): + buf.write_u32(value) + +class _UniffiConverterInt32(_UniffiConverterPrimitiveInt): + CLASS_NAME = "i32" + VALUE_MIN = -2**31 + VALUE_MAX = 2**31 + + @staticmethod + def read(buf): + return buf.read_i32() + + @staticmethod + def write_unchecked(value, buf): + buf.write_i32(value) + +class _UniffiConverterString: + @staticmethod + def check(value): + if not isinstance(value, str): + raise TypeError("argument must be str, not {}".format(type(value).__name__)) + return value + + @staticmethod + def read(buf): + size = buf.read_i32() + if size < 0: + raise InternalError("Unexpected negative string length") + utf8_bytes = buf.read(size) + return utf8_bytes.decode("utf-8") + + @staticmethod + def write(value, buf): + value = _UniffiConverterString.check(value) + utf8_bytes = value.encode("utf-8") + buf.write_i32(len(utf8_bytes)) + buf.write(utf8_bytes) + + @staticmethod + def lift(buf): + with buf.consume_with_stream() as stream: + return stream.read(stream.remaining()).decode("utf-8") + + @staticmethod + def lower(value): + value = _UniffiConverterString.check(value) + with _UniffiRustBuffer.alloc_with_builder() as builder: + builder.write(value.encode("utf-8")) + return builder.finalize() + +class _UniffiConverterBytes(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + size = buf.read_i32() + if size < 0: + raise InternalError("Unexpected negative byte string length") + return buf.read(size) + + @staticmethod + def write(value, buf): + try: + memoryview(value) + except TypeError: + raise TypeError("a bytes-like object is required, not {!r}".format(type(value).__name__)) + buf.write_i32(len(value)) + buf.write(value) + + +class ImageData: + image: "bytes";width: "int";height: "int"; + + @typing.no_type_check + def __init__(self, image: "bytes", width: "int", height: "int"): + self.image = image + self.width = width + self.height = height + + def __str__(self): + return "ImageData(image={}, width={}, height={})".format(self.image, self.width, self.height) + + def __eq__(self, other): + if self.image != other.image: + return False + if self.width != other.width: + return False + if self.height != other.height: + return False + return True + +class _UniffiConverterTypeImageData(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ImageData( + image=_UniffiConverterBytes.read(buf), + width=_UniffiConverterUInt32.read(buf), + height=_UniffiConverterUInt32.read(buf), + ) + + @staticmethod + def write(value, buf): + _UniffiConverterBytes.write(value.image, buf) + _UniffiConverterUInt32.write(value.width, buf) + _UniffiConverterUInt32.write(value.height, buf) + + +class MonitorData: + width: "int";height: "int";x: "int";y: "int";name: "str"; + + @typing.no_type_check + def __init__(self, width: "int", height: "int", x: "int", y: "int", name: "str"): + self.width = width + self.height = height + self.x = x + self.y = y + self.name = name + + def __str__(self): + return "MonitorData(width={}, height={}, x={}, y={}, name={})".format(self.width, self.height, self.x, self.y, self.name) + + def __eq__(self, other): + if self.width != other.width: + return False + if self.height != other.height: + return False + if self.x != other.x: + return False + if self.y != other.y: + return False + if self.name != other.name: + return False + return True + +class _UniffiConverterTypeMonitorData(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return MonitorData( + width=_UniffiConverterUInt32.read(buf), + height=_UniffiConverterUInt32.read(buf), + x=_UniffiConverterInt32.read(buf), + y=_UniffiConverterInt32.read(buf), + name=_UniffiConverterString.read(buf), + ) + + @staticmethod + def write(value, buf): + _UniffiConverterUInt32.write(value.width, buf) + _UniffiConverterUInt32.write(value.height, buf) + _UniffiConverterInt32.write(value.x, buf) + _UniffiConverterInt32.write(value.y, buf) + _UniffiConverterString.write(value.name, buf) + +def capture_fullscreen() -> "ImageData": + return _UniffiConverterTypeImageData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_capture_fullscreen,)) + + +def capture_monitor(name: "str") -> "ImageData": + + return _UniffiConverterTypeImageData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_capture_monitor, + _UniffiConverterString.lower(name))) + + +def capture_rect(x: "int",y: "int",width: "int",height: "int") -> "ImageData": + + + + + return _UniffiConverterTypeImageData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_capture_rect, + _UniffiConverterUInt32.lower(x), + _UniffiConverterUInt32.lower(y), + _UniffiConverterUInt32.lower(width), + _UniffiConverterUInt32.lower(height))) + + +def capture_window(x: "int",y: "int") -> "ImageData": + + + return _UniffiConverterTypeImageData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_capture_window, + _UniffiConverterUInt32.lower(x), + _UniffiConverterUInt32.lower(y))) + + +def get_monitor(x: "int",y: "int") -> "MonitorData": + + + return _UniffiConverterTypeMonitorData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_get_monitor, + _UniffiConverterUInt32.lower(x), + _UniffiConverterUInt32.lower(y))) + + +def get_primary_monitor() -> "MonitorData": + return _UniffiConverterTypeMonitorData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_get_primary_monitor,)) + + +def get_screen_dimensions(name: "str") -> "MonitorData": + + return _UniffiConverterTypeMonitorData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_get_screen_dimensions, + _UniffiConverterString.lower(name))) + + +def get_working_area() -> "MonitorData": + return _UniffiConverterTypeMonitorData.lift(_rust_call(_UniffiLib.uniffi_snapxrust_fn_func_get_working_area,)) + + +__all__ = [ + "InternalError", + "ImageData", + "MonitorData", + "capture_fullscreen", + "capture_monitor", + "capture_rect", + "capture_window", + "get_monitor", + "get_primary_monitor", + "get_screen_dimensions", + "get_working_area", +] + diff --git a/SnapX.Core/ScreenCapture/Rust/build.rs b/SnapX.Core/SharpCapture/Rust/build.rs similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/build.rs rename to SnapX.Core/SharpCapture/Rust/build.rs diff --git a/SnapX.Core/ScreenCapture/Rust/src/lib.rs b/SnapX.Core/SharpCapture/Rust/src/lib.rs similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/src/lib.rs rename to SnapX.Core/SharpCapture/Rust/src/lib.rs diff --git a/SnapX.Core/ScreenCapture/Rust/src/snapxrust.udl b/SnapX.Core/SharpCapture/Rust/src/snapxrust.udl similarity index 100% rename from SnapX.Core/ScreenCapture/Rust/src/snapxrust.udl rename to SnapX.Core/SharpCapture/Rust/src/snapxrust.udl diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/FFmpegCaptureDevice.cs b/SnapX.Core/SharpCapture/ScreenRecording/FFmpegCaptureDevice.cs similarity index 95% rename from SnapX.Core/ScreenCapture/ScreenRecording/FFmpegCaptureDevice.cs rename to SnapX.Core/SharpCapture/ScreenRecording/FFmpegCaptureDevice.cs index 46d2cf1a3..f809f9e73 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/FFmpegCaptureDevice.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/FFmpegCaptureDevice.cs @@ -1,8 +1,7 @@ - // SPDX-License-Identifier: GPL-3.0-or-later -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public class FFmpegCaptureDevice { diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/FFmpegOptions.cs b/SnapX.Core/SharpCapture/ScreenRecording/FFmpegOptions.cs similarity index 99% rename from SnapX.Core/ScreenCapture/ScreenRecording/FFmpegOptions.cs rename to SnapX.Core/SharpCapture/ScreenRecording/FFmpegOptions.cs index 81c821ce8..c64487e1c 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/FFmpegOptions.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/FFmpegOptions.cs @@ -2,7 +2,7 @@ using SnapX.Core.Utils; -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public class FFmpegOptions { diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/HardDiskCache.cs b/SnapX.Core/SharpCapture/ScreenRecording/HardDiskCache.cs similarity index 95% rename from SnapX.Core/ScreenCapture/ScreenRecording/HardDiskCache.cs rename to SnapX.Core/SharpCapture/ScreenRecording/HardDiskCache.cs index 08d68375e..cbd0e8602 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/HardDiskCache.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/HardDiskCache.cs @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later using SixLabors.ImageSharp; -using SnapX.Core.ScreenCapture.Helpers; +using SnapX.Core.SharpCapture.Helpers; using SnapX.Core.Utils; using SnapX.Core.Utils.Extensions; -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public class HardDiskCache : ImageCache { diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/ImageCache.cs b/SnapX.Core/SharpCapture/ScreenRecording/ImageCache.cs similarity index 97% rename from SnapX.Core/ScreenCapture/ScreenRecording/ImageCache.cs rename to SnapX.Core/SharpCapture/ScreenRecording/ImageCache.cs index e583734c7..9038b0cdb 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/ImageCache.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/ImageCache.cs @@ -1,11 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Collections.Concurrent; using SixLabors.ImageSharp; -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public abstract class ImageCache : IDisposable { diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecorder.cs b/SnapX.Core/SharpCapture/ScreenRecording/ScreenRecorder.cs similarity index 99% rename from SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecorder.cs rename to SnapX.Core/SharpCapture/ScreenRecording/ScreenRecorder.cs index b28195deb..e0f807fac 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecorder.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/ScreenRecorder.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -8,7 +7,7 @@ using SnapX.Core.Media; using SnapX.Core.Utils; -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public class ScreenRecorder : IDisposable { diff --git a/SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecordingOptions.cs b/SnapX.Core/SharpCapture/ScreenRecording/ScreenRecordingOptions.cs similarity index 99% rename from SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecordingOptions.cs rename to SnapX.Core/SharpCapture/ScreenRecording/ScreenRecordingOptions.cs index 9989fbd32..6dfda361f 100644 --- a/SnapX.Core/ScreenCapture/ScreenRecording/ScreenRecordingOptions.cs +++ b/SnapX.Core/SharpCapture/ScreenRecording/ScreenRecordingOptions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,7 +5,7 @@ using System.Text; using SixLabors.ImageSharp; -namespace SnapX.Core.ScreenCapture.ScreenRecording; +namespace SnapX.Core.SharpCapture.ScreenRecording; public class ScreenRecordingOptions { diff --git a/SnapX.Core/SharpCapture/Services/CaptureService.cs b/SnapX.Core/SharpCapture/Services/CaptureService.cs new file mode 100644 index 000000000..98f63a95a --- /dev/null +++ b/SnapX.Core/SharpCapture/Services/CaptureService.cs @@ -0,0 +1,32 @@ +using SixLabors.ImageSharp; +using SnapX.Core.Job; +using SnapX.Core.SharpCapture.Interfaces; +using SnapX.Core.Utils.Native; + +namespace SnapX.Core.SharpCapture.Services; + +public class CaptureService(BaseSharpCapture _baseCapture, INativeAPI _nativeAPI) : ICaptureService +{ + public async Task CaptureActiveMonitorAsync(TaskSettings? taskSettings = null) + { + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); + var bounds = await _baseCapture.GetScreen(_nativeAPI.GetCursorPosition()); + + return await _baseCapture.CaptureScreen(bounds, taskSettings); + } + + public async Task CaptureFullscreenAsync(TaskSettings? taskSettings = null) + { + throw new NotImplementedException(); + } + + public async Task CaptureRectangle(TaskSettings? taskSettings = null, Rectangle? rect = null) + { + throw new NotImplementedException(); + } + + public async Task CaptureActiveWindowAsync(TaskSettings? taskSettings = null) + { + throw new NotImplementedException(); + } +} diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b1nzyblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/b1nzyblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b1nzyblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/b1nzyblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b1nzyblob2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/b1nzyblob2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b1nzyblob2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/b1nzyblob2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b4nzyblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/b4nzyblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/b4nzyblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/b4nzyblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob0w0.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob0w0.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob0w0.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob0w0.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob3c.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob3c.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob3c.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob3c.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob3cevil.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob3cevil.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blob3cevil.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blob3cevil.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaffection.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaffection.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaffection.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaffection.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobamused.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobamused.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobamused.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobamused.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangel.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangel.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangel.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangel.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangery.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangery.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangery.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangery.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangry.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangry.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangry.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangry.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangry2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangry2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangry2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangry2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangrypuff.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangrypuff.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobangrypuff.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobangrypuff.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobartist.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobartist.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobartist.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobartist.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaviator.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaviator.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaviator.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaviator.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobawkward.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobawkward.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobawkward.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobawkward.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaww.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaww.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobaww.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobaww.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbandage.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbandage.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbandage.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbandage.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbanhammer.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbanhammer.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbanhammer.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbanhammer.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbathtub.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbathtub.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbathtub.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbathtub.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobblackcat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobblackcat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobblackcat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobblackcat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobblush.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobblush.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobblush.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobblush.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobboost.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobboost.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobboost.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobboost.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbored.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbored.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbored.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbored.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbot.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbot.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbot.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbot.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbowing.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbowing.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbowing.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbowing.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbroken.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbroken.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobbroken.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobbroken.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcamera.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcamera.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcamera.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcamera.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheeky.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheeky.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheeky.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheeky.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheer.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheer.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheer.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheer.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheerful.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheerful.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheerful.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheerful.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheerful2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheerful2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcheerful2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcheerful2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobclipboard.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobclipboard.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobclipboard.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobclipboard.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcmereyou.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcmereyou.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcmereyou.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcmereyou.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcocoa.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcocoa.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcocoa.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcocoa.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcomfort.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcomfort.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcomfort.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcomfort.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconcerned.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconcerned.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconcerned.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconcerned.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconfounded.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconfounded.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconfounded.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconfounded.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconfused.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconfused.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobconfused.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobconfused.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcool.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcool.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcool.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcool.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcouncil.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcouncil.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcouncil.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcouncil.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcouple.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcouple.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcouple.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcouple.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcowboy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcowboy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcowboy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcowboy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcry.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcry.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobcry.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobcry.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdancer.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdancer.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdancer.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdancer.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdead.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdead.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdead.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdead.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobderpy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobderpy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobderpy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobderpy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobderpyhappy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobderpyhappy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobderpyhappy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobderpyhappy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdetective.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdetective.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdetective.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdetective.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdevil.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdevil.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdevil.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdevil.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdevilsmile.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdevilsmile.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdevilsmile.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdevilsmile.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdisapproval.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdisapproval.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdisapproval.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdisapproval.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdisguise.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdisguise.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdisguise.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdisguise.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdizzy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdizzy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdizzy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdizzy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdizzy2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdizzy2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdizzy2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdizzy2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoctor.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoctor.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoctor.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoctor.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoubt.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoubt.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoubt.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoubt.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoubtful.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoubtful.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdoubtful.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdoubtful.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdrool.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdrool.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobdrool.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobdrool.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeagle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeagle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeagle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeagle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobembarrassed.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobembarrassed.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobembarrassed.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobembarrassed.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobembarrassed2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobembarrassed2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobembarrassed2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobembarrassed2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobenjoy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobenjoy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobenjoy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobenjoy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloberm.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloberm.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloberm.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloberm.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobexpressionless.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobexpressionless.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobexpressionless.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobexpressionless.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeyesdown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeyesdown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeyesdown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeyesdown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeyesup.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeyesup.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobeyesup.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobeyesup.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfacemask.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfacemask.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfacemask.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfacemask.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfacepalm.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfacepalm.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfacepalm.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfacepalm.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfearful.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfearful.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfearful.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfearful.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfingerguns.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfingerguns.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfingerguns.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfingerguns.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfingerscrossed.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfingerscrossed.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfingerscrossed.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfingerscrossed.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfirefighter.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfirefighter.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfirefighter.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfirefighter.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfistbumpL.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfistbumpL.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfistbumpL.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfistbumpL.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfistbumpR.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfistbumpR.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfistbumpR.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfistbumpR.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobflushed.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobflushed.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobflushed.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobflushed.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfreezing.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfreezing.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfreezing.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfreezing.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrog.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrog.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrog.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrog.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrowning.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrowning.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrowning.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrowning.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrowningbig.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrowningbig.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobfrowningbig.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobfrowningbig.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgamer.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgamer.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgamer.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgamer.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgift.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgift.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgift.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgift.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgiggle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgiggle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgiggle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgiggle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglare.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglare.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglare.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglare.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglarepolice.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglarepolice.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglarepolice.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglarepolice.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglassesdown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglassesdown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobglassesdown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobglassesdown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgo.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgo.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgo.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgo.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodmorning.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodmorning.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodmorning.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodmorning.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodmorningreverse.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodmorningreverse.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodmorningreverse.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodmorningreverse.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodnight.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodnight.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodnight.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodnight.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodnightreverse.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodnightreverse.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgoodnightreverse.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgoodnightreverse.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrimace.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrimace.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrimace.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrimace.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrin.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrin.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrin.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrin.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrumpy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrumpy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobgrumpy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobgrumpy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobheart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobheart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobheart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobheart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhearteyes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhearteyes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhearteyes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhearteyes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhero.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhero.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhero.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhero.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhighfive.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhighfive.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhighfive.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhighfive.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhug.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhug.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhug.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhug.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhug2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhug2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhug2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhug2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhuh.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhuh.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhuh.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhuh.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhushed.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhushed.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhushed.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhushed.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhyperthink.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhyperthink.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhyperthink.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhyperthink.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhyperthinkfast.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhyperthinkfast.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhyperthinkfast.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhyperthinkfast.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhypesquad.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhypesquad.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobhypesquad.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobhypesquad.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobidea.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobidea.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobidea.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobidea.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobimfine.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobimfine.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobimfine.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobimfine.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobinlove.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobinlove.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobinlove.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobinlove.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobjam.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobjam.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobjam.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobjam.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobjoy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobjoy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobjoy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobjoy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkiss.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkiss.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkiss.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkiss.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkissblush.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkissblush.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkissblush.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkissblush.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkissheart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkissheart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobkissheart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobkissheart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloblamp.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloblamp.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloblamp.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloblamp.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloblul.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloblul.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloblul.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloblul.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmail.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmail.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmail.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmail.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmaracas.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmaracas.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmaracas.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmaracas.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmelt.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmelt.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmelt.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmelt.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltblush.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltblush.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltblush.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltblush.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltsob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltsob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltsob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltsob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltsoblove.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltsoblove.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmeltsoblove.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmeltsoblove.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmindblown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmindblown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmindblown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmindblown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmlem.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmlem.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmlem.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmlem.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmorning.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmorning.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmorning.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmorning.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmoustache.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmoustache.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobmoustache.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobmoustache.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnauseated.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnauseated.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnauseated.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnauseated.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnerd.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnerd.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnerd.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnerd.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervous.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervous.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervous.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervous.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervous2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervous2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervous2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervous2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervouspleading.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervouspleading.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnervouspleading.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnervouspleading.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobneutral.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobneutral.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobneutral.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobneutral.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnight.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnight.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnight.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnight.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobninja.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobninja.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobninja.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobninja.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnitro.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnitro.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnitro.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnitro.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobno.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobno.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobno.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobno.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnogood.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnogood.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnogood.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnogood.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnom.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnom.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnom.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnom.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomchocolate.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomchocolate.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomchocolate.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomchocolate.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomchristmas.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomchristmas.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomchristmas.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomchristmas.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomcookie.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomcookie.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomcookie.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomcookie.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal1.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal1.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal1.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal1.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal3.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal3.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomglobal3.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomglobal3.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomouth.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomouth.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnomouth.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnomouth.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnook.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnook.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnook.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnook.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnostar.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnostar.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnostar.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnostar.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnostar2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnostar2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnostar2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnostar2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnwn.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnwn.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobnwn.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobnwn.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobok.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobok.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobok.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobok.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobokhand.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobokhand.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobokhand.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobokhand.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobomo.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobomo.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobomo.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobomo.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobonfire.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobonfire.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobonfire.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobonfire.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobono.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobono.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobono.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobono.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobooh.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobooh.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobooh.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobooh.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboohcry.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboohcry.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboohcry.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboohcry.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobopenmouth.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobopenmouth.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobopenmouth.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobopenmouth.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboro.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboro.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboro.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboro.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboutage.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboutage.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboutage.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboutage.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboverheated.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboverheated.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bloboverheated.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bloboverheated.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobovo.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobovo.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobovo.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobovo.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowo.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowo.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowo.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowo.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowo2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowo2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowo2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowo2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowoevil.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowoevil.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowoevil.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowoevil.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowosquint.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowosquint.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobowosquint.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobowosquint.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpain.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpain.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpain.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpain.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpainpats.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpainpats.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpainpats.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpainpats.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpan.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpan.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpan.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpan.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpanic.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpanic.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpanic.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpanic.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpanic2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpanic2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpanic2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpanic2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpartlysunny.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpartlysunny.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpartlysunny.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpartlysunny.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobparty.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobparty.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobparty.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobparty.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpatrol.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpatrol.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpatrol.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpatrol.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpats.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpats.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpats.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpats.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpeek.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpeek.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpeek.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpeek.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpensive.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpensive.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpensive.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpensive.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpensivepray.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpensivepray.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpensivepray.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpensivepray.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpin.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpin.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpin.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpin.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpirate.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpirate.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpirate.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpirate.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpleading.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpleading.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpleading.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpleading.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpolice.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpolice.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpolice.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpolice.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpoliceangery.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpoliceangery.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpoliceangery.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpoliceangery.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpoll.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpoll.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpoll.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpoll.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpopcorn.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpopcorn.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpopcorn.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpopcorn.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpopsicle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpopsicle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpopsicle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpopsicle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpout.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpout.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpout.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpout.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpout2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpout2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpout2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpout2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpray.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpray.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpray.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpray.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpumpkin.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpumpkin.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobpumpkin.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobpumpkin.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrage.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrage.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrage.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrage.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrageangry.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrageangry.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrageangry.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrageangry.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreach.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreach.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreach.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreach.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachdrool.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachdrool.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachdrool.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachdrool.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachfront.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachfront.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachfront.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachfront.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachfrown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachfrown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachfrown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachfrown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachreverse.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachreverse.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachreverse.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachreverse.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachsob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachsob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobreachsob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobreachsob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrelieved.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrelieved.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrelieved.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrelieved.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrofl.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrofl.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrofl.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrofl.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrollingeyes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrollingeyes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobrollingeyes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobrollingeyes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobross.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobross.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobross.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobross.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsad.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsad.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsad.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsad.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsadpats.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsadpats.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsadpats.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsadpats.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsadrain.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsadrain.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsadrain.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsadrain.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsalute.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsalute.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsalute.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsalute.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsanta.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsanta.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsanta.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsanta.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobscarf.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobscarf.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobscarf.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobscarf.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobscream.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobscream.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobscream.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobscream.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsecret.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsecret.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsecret.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsecret.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobshh.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobshh.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobshh.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobshh.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobshrug.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobshrug.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobshrug.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobshrug.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsick.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsick.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsick.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsick.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsip.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsip.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsip.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsip.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsleeping.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsleeping.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsleeping.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsleeping.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsleepless.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsleepless.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsleepless.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsleepless.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobslightsmile.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobslightsmile.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobslightsmile.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobslightsmile.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmile.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmile.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmile.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmile.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilehappy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilehappy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilehappy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilehappy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilehappyeyes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilehappyeyes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilehappyeyes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilehappyeyes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilesweat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilesweat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilesweat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilesweat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilesweat2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilesweat2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmilesweat2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmilesweat2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmiletear.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmiletear.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmiletear.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmiletear.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmiley.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmiley.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmiley.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmiley.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmirk.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmirk.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmirk.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmirk.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmirk2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmirk2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsmirk2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsmirk2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsneezing.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsneezing.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsneezing.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsneezing.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsnuggle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsnuggle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsnuggle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsnuggle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsobglasses.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsobglasses.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsobglasses.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsobglasses.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobspam.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobspam.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobspam.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobspam.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsplosion.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsplosion.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsplosion.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsplosion.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobspy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobspy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobspy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobspy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsquee.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsquee.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsquee.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsquee.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstare.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstare.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstare.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstare.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstarstruck.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstarstruck.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstarstruck.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstarstruck.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstop.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstop.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstop.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstop.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstudent.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstudent.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobstudent.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobstudent.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsunglasses.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsunglasses.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsunglasses.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsunglasses.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsurprised.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsurprised.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsurprised.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsurprised.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsus.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsus.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsus.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsus.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsweats.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsweats.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsweats.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsweats.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsweatsweary.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsweatsweary.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobsweatsweary.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobsweatsweary.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobteefs.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobteefs.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobteefs.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobteefs.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthanks.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthanks.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthanks.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthanks.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthief.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthief.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthief.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthief.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinking.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinking.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinking.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinking.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingcool.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingcool.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingcool.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingcool.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingdown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingdown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingdown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingdown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingeyes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingeyes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingeyes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingeyes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingfast.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingfast.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingfast.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingfast.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingglare.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingglare.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingglare.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingglare.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingsmirk.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingsmirk.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinkingsmirk.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinkingsmirk.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinksmart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinksmart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthinksmart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthinksmart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthis.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthis.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthis.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthis.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthonkang.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthonkang.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthonkang.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthonkang.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthumbsdown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthumbsdown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthumbsdown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthumbsdown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthumbsup.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthumbsup.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthumbsup.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthumbsup.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthump.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthump.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobthump.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobthump.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtilt.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtilt.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtilt.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtilt.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtired.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtired.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtired.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtired.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtongue.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtongue.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtongue.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtongue.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtonguewink.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtonguewink.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtonguewink.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtonguewink.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtorch.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtorch.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtorch.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtorch.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtrans.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtrans.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtrans.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtrans.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtriumph.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtriumph.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtriumph.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtriumph.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtriumph2.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtriumph2.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobtriumph2.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobtriumph2.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobugh.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobugh.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobugh.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobugh.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobunamused.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobunamused.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobunamused.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobunamused.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobunsure.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobunsure.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobunsure.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobunsure.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobupset.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobupset.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobupset.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobupset.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobupsidedown.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobupsidedown.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobupsidedown.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobupsidedown.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobuwu.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobuwu.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobuwu.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobuwu.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobvomiting.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobvomiting.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobvomiting.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobvomiting.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwaitwhat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwaitwhat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwaitwhat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwaitwhat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwave.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwave.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwave.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwave.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwavereverse.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwavereverse.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwavereverse.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwavereverse.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwavesob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwavesob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwavesob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwavesob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobweary.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobweary.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobweary.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobweary.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwhistle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwhistle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwhistle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwhistle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwink.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwink.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwink.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwink.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwitch.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwitch.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwitch.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwitch.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwizard.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwizard.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwizard.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwizard.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoah.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoah.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoah.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoah.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoahopenmouth.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoahopenmouth.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoahopenmouth.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoahopenmouth.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwooloo.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwooloo.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwooloo.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwooloo.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoozy.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoozy.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobwoozy.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobwoozy.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobworker.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobworker.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobworker.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobworker.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobworried.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobworried.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobworried.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobworried.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobxd.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobxd.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobxd.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobxd.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyawn.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyawn.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyawn.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyawn.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyikes.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyikes.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyikes.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyikes.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyum.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyum.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobyum.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobyum.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobzippermouth.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobzippermouth.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/blobzippermouth.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/blobzippermouth.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bolb.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/bolb.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/bolb.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/bolb.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/doggoblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/doggoblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/doggoblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/doggoblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/feelsblobman.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/feelsblobman.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/feelsblobman.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/feelsblobman.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/ferretblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/ferretblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/ferretblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/ferretblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/gentleblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/gentleblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/gentleblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/gentleblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebear.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebear.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebear.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebear.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebee.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebee.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebee.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebee.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebird.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebird.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlebird.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlebird.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleblueheart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleblueheart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleblueheart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleblueheart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecake.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecake.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecake.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecake.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecatface.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecatface.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecatface.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecatface.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecatheart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecatheart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecatheart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecatheart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechick.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechick.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechick.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechick.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechicken.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechicken.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechicken.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechicken.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechristmastree.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechristmastree.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlechristmastree.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlechristmastree.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecow.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecow.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecow.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecow.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecrab.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecrab.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlecrab.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlecrab.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googledog.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googledog.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googledog.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googledog.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googledove.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googledove.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googledove.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googledove.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleduck.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleduck.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleduck.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleduck.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleeagle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleeagle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleeagle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleeagle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlefire.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlefire.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlefire.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlefire.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlefox.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlefox.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlefox.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlefox.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleghost.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleghost.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleghost.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleghost.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegift.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegift.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegift.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegift.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegoat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegoat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegoat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegoat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegun.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegun.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlegun.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlegun.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleicecream.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleicecream.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleicecream.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleicecream.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlekoala.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlekoala.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlekoala.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlekoala.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlelion.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlelion.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlelion.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlelion.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemouse.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemouse.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemouse.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemouse.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemuscleL.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemuscleL.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemuscleL.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemuscleL.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemuscleR.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemuscleR.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlemuscleR.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlemuscleR.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleoctopus.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleoctopus.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleoctopus.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleoctopus.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepanda.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepanda.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepanda.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepanda.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepenguin.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepenguin.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepenguin.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepenguin.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepig.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepig.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepig.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepig.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepizza.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepizza.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlepizza.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlepizza.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlerabbit.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlerabbit.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlerabbit.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlerabbit.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlerat.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlerat.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlerat.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlerat.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleredheart.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleredheart.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleredheart.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleredheart.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlescorpion.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlescorpion.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlescorpion.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlescorpion.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesheep.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesheep.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesheep.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesheep.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesnail.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesnail.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesnail.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesnail.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesnake.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesnake.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesnake.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesnake.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesquirrel.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesquirrel.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlesquirrel.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlesquirrel.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleturtle.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleturtle.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googleturtle.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googleturtle.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlewhale.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlewhale.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/googlewhale.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/googlewhale.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/greentick.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/greentick.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/greentick.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/greentick.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/jakeblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/jakeblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/jakeblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/jakeblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/kirbyblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/kirbyblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/kirbyblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/kirbyblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/nellyblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/nellyblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/nellyblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/nellyblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/nikoblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/nikoblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/nikoblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/nikoblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/notlikeblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/notlikeblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/notlikeblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/notlikeblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pandablob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/pandablob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pandablob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/pandablob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/photoblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/photoblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/photoblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/photoblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pikablob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/pikablob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pikablob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/pikablob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pusheenblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/pusheenblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/pusheenblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/pusheenblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/rainblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/rainblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/rainblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/rainblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/redtick.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/redtick.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/redtick.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/redtick.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/reindeerblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/reindeerblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/reindeerblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/reindeerblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/rickblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/rickblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/rickblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/rickblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/superblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/superblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/superblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/superblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/thinkingwithblobs.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/thinkingwithblobs.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/thinkingwithblobs.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/thinkingwithblobs.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/wolfiriblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/wolfiriblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/wolfiriblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/wolfiriblob.png diff --git a/SnapX.Core/ScreenCapture/Stickers/BlobEmoji/wumpusblob.png b/SnapX.Core/SharpCapture/Stickers/BlobEmoji/wumpusblob.png similarity index 100% rename from SnapX.Core/ScreenCapture/Stickers/BlobEmoji/wumpusblob.png rename to SnapX.Core/SharpCapture/Stickers/BlobEmoji/wumpusblob.png diff --git a/SnapX.Core/SharpCapture/Windows/WindowsCapture.cs b/SnapX.Core/SharpCapture/Windows/WindowsCapture.cs index 46be2d75f..27ab3c8da 100644 --- a/SnapX.Core/SharpCapture/Windows/WindowsCapture.cs +++ b/SnapX.Core/SharpCapture/Windows/WindowsCapture.cs @@ -10,13 +10,14 @@ using Windows.Graphics.DirectX; using Windows.Graphics.DirectX.Direct3D11; using Windows.Win32; +using SnapX.Core.Job; using WinRT; namespace SnapX.Core.SharpCapture.Windows; [SupportedOSPlatform("windows10.0.19045")] -public class WindowsCapture : BaseCapture +public class WindowsCapture : BaseSharpCapture { private bool IsSupportedFeatureLevel(IDXGIAdapter1 adapter, FeatureLevel featureLevel, DeviceCreationFlags creationFlags) @@ -40,7 +41,7 @@ private bool IsSupportedFeatureLevel(IDXGIAdapter1 adapter, FeatureLevel feature return false; } - public override async Task CaptureFullscreen() + public override async Task CaptureFullscreen(TaskSettings? taskSettings = null) { var factory = DXGI.CreateDXGIFactory1()!; @@ -103,7 +104,7 @@ private bool IsSupportedFeatureLevel(IDXGIAdapter1 adapter, FeatureLevel feature } - public override async Task CaptureScreen(Point? pos) + public override async Task CaptureScreen(Point? pos, TaskSettings? taskSettings = null) { var factory = DXGI.CreateDXGIFactory1()!; @@ -184,7 +185,7 @@ private static ID3D11Texture2D Texture2DFromSurface(IDirect3DSurface surface) var texture = access.QueryInterface(); return texture; } - public override async Task CaptureWindow(Point pos) + public override async Task CaptureWindow(Point pos, TaskSettings? taskSettings = null) { if (!GraphicsCaptureSession.IsSupported()) { diff --git a/SnapX.Core/SharpCapture/macOS/macOSCapture.cs b/SnapX.Core/SharpCapture/macOS/macOSCapture.cs index e05f48e50..0b3a31dd6 100644 --- a/SnapX.Core/SharpCapture/macOS/macOSCapture.cs +++ b/SnapX.Core/SharpCapture/macOS/macOSCapture.cs @@ -1,4 +1,5 @@ using SixLabors.ImageSharp; +using SnapX.Core.Job; using SnapX.Core.Utils; using SnapX.Core.Utils.Native; using uniffi.snapxrust; @@ -319,29 +320,29 @@ namespace SnapX.Core.SharpCapture.macOS; // } // } -public class macOSCapture : BaseCapture +public class macOSCapture : BaseSharpCapture { - public override async Task CaptureFullscreen() + public override async Task CaptureFullscreen(TaskSettings? taskSettings = null) { return ImageHelpers.ImageDataToImage(SnapxrustMethods.CaptureFullscreen()); } - public override async Task CaptureScreen(Rectangle bounds) + public override async Task CaptureScreen(Rectangle bounds, TaskSettings? taskSettings = null) { return CaptureRectangleNative(bounds); } - public override async Task CaptureScreen(Point? pos) + public override async Task CaptureScreen(Point? pos, TaskSettings? taskSettings = null) { return CaptureMonitor(Methods.GetCursorPosition()); } - public override async Task CaptureRectangle(Rectangle rect) + public override async Task CaptureRectangle(Rectangle rect, TaskSettings? taskSettings = null) { return CaptureRectangleNative(rect); } - public override async Task CaptureWindow(Point pos) + public override async Task CaptureWindow(Point pos, TaskSettings? taskSettings = null) { return ImageHelpers.ImageDataToImage(SnapxrustMethods.CaptureWindow((uint)pos.X, (uint)pos.Y)); } diff --git a/SnapX.Core/SnapX.Core.csproj b/SnapX.Core/SnapX.Core.csproj index 59966636f..31172f869 100644 --- a/SnapX.Core/SnapX.Core.csproj +++ b/SnapX.Core/SnapX.Core.csproj @@ -48,6 +48,7 @@ + @@ -55,11 +56,6 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - @@ -71,7 +67,6 @@ - @@ -80,6 +75,7 @@ while these are only useful for Linux, hiding them behind a compiler conditional makes debugging more difficult. --> + @@ -116,17 +112,15 @@ - + - + - - - + diff --git a/SnapX.Core/SnapX.cs b/SnapX.Core/SnapX.cs index 04606c0b1..5b253bf78 100644 --- a/SnapX.Core/SnapX.cs +++ b/SnapX.Core/SnapX.cs @@ -1,16 +1,18 @@ using System.Diagnostics; -using System.Reflection; using System.Text; using System.Text.Json; using Aptabase.Core; using Dapper; using Microsoft.Data.Sqlite; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; using SnapX.Core.CLI; using SnapX.Core.Hotkey; +using SnapX.Core.Interfaces; using SnapX.Core.Job; +using SnapX.Core.Services; using SnapX.Core.Upload; using SnapX.Core.Utils; using SnapX.Core.Utils.Extensions; @@ -23,7 +25,7 @@ namespace SnapX.Core; -public class SnapX +public class SnapX(IServiceProvider serviceProvider) { public const string AppName = "SnapX"; public static string Qualifier { get; set; } = ""; @@ -88,6 +90,18 @@ public static void quit() { CloseSequence(); } + + public static void ConfigureServices(ServiceCollection services) + { + services.AddLogging(loggingBuilder => + loggingBuilder.AddSerilog(dispose: true)); + services.AddSingleton(_ => new SerilogLogService(LogsFilePath, true, Configuration)); + services.AddSingleton(provider => + { + var logger = provider.GetRequiredService(); + return new VersionEnforcer(LockDirectory, logger); + }); + } public static string Title { get @@ -119,13 +133,13 @@ public static string Title public static bool IgnoreHotkeyWarning { get; private set; } public static bool PuushMode { get; private set; } - public static RootConfiguration Settings { get; set; } = new(); + public static ApplicationConfig Settings { get; set; } = new(); public static List Flags { get; set; } = new(); internal static IConfiguration Configuration { get; set; } - internal static TaskSettings DefaultTaskSettings { get; set; } = TaskSettings.GetDefaultTaskSettings(); - internal static UploadersConfig UploadersConfig { get; set; } - internal static HotkeysConfig HotkeysConfig { get; set; } + internal static TaskSettings? DefaultTaskSettings { get; set; } = TaskSettings.GetDefaultTaskSettings(); + internal static UploadersConfig? UploadersConfig { get; set; } = new(); + internal static HotkeysConfig? HotkeysConfig { get; set; } = new(); internal static Stopwatch StartTimer { get; private set; } internal static HotkeyManager HotkeyManager { get; set; } @@ -162,11 +176,10 @@ private static string PersonalPathConfigFilePath AppName, PersonalPathConfigFileName); private static readonly string PortableCheckFilePath = FileHelpers.GetAbsolutePath("Portable"); - public static EventAggregator EventAggregator { get; } = new(); private static string CustomPersonalPath { get; set; } private static string CustomConfigPath { get; set; } - public static SqliteConnection DbConnection { get; set; } + public static SqliteConnection? DbConnection { get; set; } public static string ShortenPath(string? path) => OperatingSystem.IsWindows() ? path : path.Replace(Environment.GetEnvironmentVariable("HOME") ?? "", "~"); @@ -263,11 +276,10 @@ public void shutdown() { CloseSequence(); } - public Assembly[] GetAssemblies() => AppDomain.CurrentDomain.GetAssemblies(); public void start(string?[] args) { HandleExceptions(); - + new SettingManager(serviceProvider).LoadSettings(); StartTimer = Stopwatch.StartNew(); // TODO: Implement CLI in a better way than what it is now. CLIManager = new SnapXCLIManager(args); @@ -290,7 +302,11 @@ public void start(string?[] args) } public long getStartupTime() => StartTimer.ElapsedMilliseconds; - public EventAggregator getEventAggregator() => EventAggregator; + public static IServiceCollection ConfigureCoreSnapXServices(IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(configuration); + return services; + } public bool isSilent() => SilentRun; public static AptabaseClient? aptabaseClient; @@ -302,8 +318,12 @@ public static bool CanUpload() => public static bool CanAutoUpdate() => !FeatureFlags.DisableAutoUpdates && Settings.AutoCheckUpdate; + public void loadApplicationSettingsPartial() + { + SettingManager.LoadApplicationConfig(); + } [DapperAot] - private static void Run() + private void Run() { DebugHelper.WriteLine("SnapX starting."); DebugHelper.WriteLine("Version: " + VersionText); @@ -371,6 +391,10 @@ private static void Run() var connectionString = new SqliteConnectionStringBuilder { DataSource = dataSource, Mode = SqliteOpenMode.ReadWriteCreate, Cache = SqliteCacheMode.Shared, ForeignKeys = true, Pooling = true, }.ToString(); DbConnection = new SqliteConnection(connectionString); RunWithTimeout(() => DbConnection.OpenAsync(), $"Opening the database connection at {DBPath}"); + RunWithTimeout(() => DbConnection.ExecuteAsync("PRAGMA busy_timeout = 5000;"), "Setting busy timeout"); + RunWithTimeout(() => DbConnection.ExecuteAsync("PRAGMA temp_store = MEMORY;"), "Setting temp_store"); + RunWithTimeout(() => DbConnection.ExecuteAsync("PRAGMA mmap_size = 30000000000;"), "Setting mmap_size"); + RunWithTimeout(() => DbConnection.ExecuteAsync("PRAGMA cache_size = -64000;"), "Setting cache_size"); RunWithTimeout(() => DbConnection.ExecuteAsync("PRAGMA journal_mode=WAL;"), "Setting journal mode"); _ = Task.Run(() => { @@ -404,7 +428,6 @@ private static void Run() { DebugHelper.WriteLine($"DB: {Args.CurrentState}"); }; - SettingManager.LoadSettings(); if (TelemetryEnabled()) { var loggerFactory = LoggerFactory.Create(builder => @@ -423,7 +446,9 @@ private static void Run() IsDebugMode = false #endif }, logger); - var telemetry = new Telemetry(DbConnection, aptabaseClient); + var loggerService = serviceProvider.GetRequiredService(); + + var telemetry = new Telemetry(DbConnection, aptabaseClient, loggerService); SnapX.aptabaseClient = aptabaseClient; telemetry.TrackEvent("app_started", new Dictionary { @@ -458,7 +483,6 @@ private static void Run() #if DEBUG options.Environment = "development"; options.CreateHttpMessageHandler = () => new LoggingHttpMessageHandler(new SentryHttpMessageHandler(), DebugHelper.Logger); - options.DisableSentryHttpMessageHandler = true; #else options.Environment = "production"; #endif @@ -518,7 +542,7 @@ static void RunWithTimeout(Func taskFactory, string description = "SQLite task.GetAwaiter().GetResult(); // propagate exceptions } public SnapXCLIManager GetCLIManager() => CLIManager; - public RootConfiguration GetConfiguration() => Settings; + public ApplicationConfig GetConfiguration() => Settings; public static void CloseSequence() { @@ -715,7 +739,7 @@ private static void HandleExceptions() #endif AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - AppDomain.CurrentDomain.ProcessExit += ((_, _) => CloseSequence()); + AppDomain.CurrentDomain.ProcessExit += (_, _) => CloseSequence(); } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) => OnError((Exception)e.ExceptionObject); private static void OnError(Exception e) => DebugHelper.WriteException(e); diff --git a/SnapX.Core/SnapXResources.cs b/SnapX.Core/SnapXResources.cs index 39c0f87b4..c47680546 100644 --- a/SnapX.Core/SnapXResources.cs +++ b/SnapX.Core/SnapXResources.cs @@ -1,9 +1,12 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using System.ComponentModel; using System.Runtime.InteropServices; +using SixLabors.ImageSharp; using SnapX.Core.Utils; +using SnapX.Core.Utils.Converters; +using SnapX.Core.Utils.Extensions; using SnapX.Core.Utils.Miscellaneous; namespace SnapX.Core; @@ -15,5 +18,240 @@ public static class SnapXResources public static OsInfo.GenericGraphicsInfo graphicsInfo => OsInfo.GetGenericGraphicsInfo(); public static string Dotnet => RuntimeInformation.FrameworkDescription; public static string fancyOsName => Helpers.GetOperatingSystemProductName(); - public static string? UserAgent => $"{SnapX.AppName}/{Helpers.GetApplicationVersion()} (+{Links.GitHub})"; + public static string UserAgent => $"{SnapX.AppName}/{Helpers.GetApplicationVersion()} (+{Links.GitHub})"; +} + + +public class Theme +{ + public string Name { get; set; } = "Dark"; + + private Color backgroundColor; + + [TypeConverter(typeof(MyColorConverter))] + public Color BackgroundColor + { + get => backgroundColor; + set + { + if (!value.IsTransparent()) backgroundColor = value; + } + } + + private Color lightBackgroundColor; + + [TypeConverter(typeof(MyColorConverter))] + public Color LightBackgroundColor + { + get => lightBackgroundColor; + set + { + if (!value.IsTransparent()) lightBackgroundColor = value; + } + } + + private Color darkBackgroundColor; + + [TypeConverter(typeof(MyColorConverter))] + public Color DarkBackgroundColor + { + get => darkBackgroundColor; + set + { + if (!value.IsTransparent()) darkBackgroundColor = value; + } + } + + private Color textColor; + + [TypeConverter(typeof(MyColorConverter))] + public Color TextColor + { + get => textColor; + set + { + if (!value.IsTransparent()) textColor = value; + } + } + + private Color borderColor; + + [TypeConverter(typeof(MyColorConverter))] + public Color BorderColor + { + get => borderColor; + set + { + if (!value.IsTransparent()) borderColor = value; + } + } + + [TypeConverter(typeof(MyColorConverter))] + public Color CheckerColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color CheckerColor2 { get; set; } + + public int CheckerSize { get; set; } = 15; + + [TypeConverter(typeof(MyColorConverter))] + public Color LinkColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color MenuHighlightColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color MenuHighlightBorderColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color MenuBorderColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color MenuCheckBackgroundColor { get; set; } + public record UIFont(string Name, float Size); + public UIFont MenuFont { get; set; } = new("Inter", 11f); + + public UIFont ContextMenuFont { get; set; } = new("Inter", 11f); + + public int ContextMenuOpacity { get; set; } = 100; + + [Browsable(false)] + public double ContextMenuOpacityDouble => ContextMenuOpacity.Clamp(10, 100) / 100d; + + [TypeConverter(typeof(MyColorConverter))] + public Color SeparatorLightColor { get; set; } + + [TypeConverter(typeof(MyColorConverter))] + public Color SeparatorDarkColor { get; set; } + + [Browsable(false)] + public bool IsDarkTheme => ColorHelpers.IsDarkColor(BackgroundColor); + + + public static Theme DarkTheme => new() + { + Name = "Dark", + BackgroundColor = Color.FromRgba(39, 39, 39, 255), + LightBackgroundColor = Color.FromRgba(46, 46, 46, 255), + DarkBackgroundColor = Color.FromRgba(34, 34, 34, 255), + TextColor = Color.FromRgba(231, 233, 234, 255), + BorderColor = Color.FromRgba(31, 31, 31, 255), + CheckerColor = Color.FromRgba(46, 46, 46, 255), + CheckerColor2 = Color.FromRgba(39, 39, 39, 255), + LinkColor = Color.FromRgba(166, 212, 255, 255), + MenuHighlightColor = Color.FromRgba(46, 46, 46, 255), + MenuHighlightBorderColor = Color.FromRgba(63, 63, 63, 255), + MenuBorderColor = Color.FromRgba(63, 63, 63, 255), + MenuCheckBackgroundColor = Color.FromRgba(51, 51, 51, 255), + SeparatorLightColor = Color.FromRgba(44, 44, 44, 255), + SeparatorDarkColor = Color.FromRgba(31, 31, 31, 255) + }; + + public static Theme LightTheme => new() + { + Name = "Light", + BackgroundColor = Color.FromRgba(242, 242, 242, 255), + LightBackgroundColor = Color.FromRgba(247, 247, 247, 255), + DarkBackgroundColor = Color.FromRgba(235, 235, 235, 255), + TextColor = Color.FromRgba(69, 69, 69, 255), + BorderColor = Color.FromRgba(201, 201, 201, 255), + CheckerColor = Color.FromRgba(247, 247, 247, 255), + CheckerColor2 = Color.FromRgba(235, 235, 235, 255), + LinkColor = Color.FromRgba(166, 212, 255, 255), + MenuHighlightColor = Color.FromRgba(247, 247, 247, 255), + MenuHighlightBorderColor = Color.FromRgba(96, 143, 226, 255), + MenuBorderColor = Color.FromRgba(201, 201, 201, 255), + MenuCheckBackgroundColor = Color.FromRgba(225, 233, 244, 255), + SeparatorLightColor = Color.FromRgba(253, 253, 253, 255), + SeparatorDarkColor = Color.FromRgba(189, 189, 189, 255) + }; + + public static Theme NightTheme => new() + { + Name = "Night", + BackgroundColor = Color.FromRgba(42, 47, 56, 255), + LightBackgroundColor = Color.FromRgba(52, 57, 65, 255), + DarkBackgroundColor = Color.FromRgba(28, 32, 38, 255), + TextColor = Color.FromRgba(235, 235, 235, 255), + BorderColor = Color.FromRgba(28, 32, 38, 255), + CheckerColor = Color.FromRgba(60, 60, 60, 255), + CheckerColor2 = Color.FromRgba(50, 50, 50, 255), + LinkColor = Color.FromRgba(166, 212, 255, 255), + MenuHighlightColor = Color.FromRgba(30, 34, 40, 255), + MenuHighlightBorderColor = Color.FromRgba(116, 129, 152, 255), + MenuBorderColor = Color.FromRgba(22, 26, 31, 255), + MenuCheckBackgroundColor = Color.FromRgba(56, 64, 75, 255), + SeparatorLightColor = Color.FromRgba(56, 64, 75, 255), + SeparatorDarkColor = Color.FromRgba(22, 26, 31, 255) + }; + + // https://www.nordtheme.com + public static Theme NordDarkTheme => new() + { + Name = "Nord Dark", + BackgroundColor = Color.FromRgba(46, 52, 64, 255), + LightBackgroundColor = Color.FromRgba(59, 66, 82, 255), + DarkBackgroundColor = Color.FromRgba(38, 44, 57, 255), + TextColor = Color.FromRgba(229, 233, 240, 255), + BorderColor = Color.FromRgba(30, 38, 54, 255), + CheckerColor = Color.FromRgba(46, 52, 64, 255), + CheckerColor2 = Color.FromRgba(36, 42, 54, 255), + LinkColor = Color.FromRgba(136, 192, 208, 255), + MenuHighlightColor = Color.FromRgba(36, 42, 54, 255), + MenuHighlightBorderColor = Color.FromRgba(24, 30, 42, 255), + MenuBorderColor = Color.FromRgba(24, 30, 42, 255), + MenuCheckBackgroundColor = Color.FromRgba(59, 66, 82, 255), + SeparatorLightColor = Color.FromRgba(59, 66, 82, 255), + SeparatorDarkColor = Color.FromRgba(30, 38, 54, 255) + }; + + // https://www.nordtheme.com + public static Theme NordLightTheme => new() + { + Name = "Nord Light", + BackgroundColor = Color.FromRgba(229, 233, 240, 255), + LightBackgroundColor = Color.FromRgba(236, 239, 244, 255), + DarkBackgroundColor = Color.FromRgba(216, 222, 233, 255), + TextColor = Color.FromRgba(59, 66, 82, 255), + BorderColor = Color.FromRgba(207, 216, 233, 255), + CheckerColor = Color.FromRgba(229, 233, 240, 255), + CheckerColor2 = Color.FromRgba(216, 222, 233, 255), + LinkColor = Color.FromRgba(106, 162, 178, 255), + MenuHighlightColor = Color.FromRgba(236, 239, 244, 255), + MenuHighlightBorderColor = Color.FromRgba(207, 216, 233, 255), + MenuBorderColor = Color.FromRgba(216, 222, 233, 255), + MenuCheckBackgroundColor = Color.FromRgba(229, 233, 240, 255), + SeparatorLightColor = Color.FromRgba(236, 239, 244, 255), + SeparatorDarkColor = Color.FromRgba(207, 216, 233, 255) + }; + + // https://draculatheme.com + public static Theme DraculaTheme => new() + { + Name = "Dracula", + BackgroundColor = Color.FromRgba(40, 42, 54, 255), + LightBackgroundColor = Color.FromRgba(68, 71, 90, 255), + DarkBackgroundColor = Color.FromRgba(36, 38, 48, 255), + TextColor = Color.FromRgba(248, 248, 242, 255), + BorderColor = Color.FromRgba(33, 35, 43, 255), + CheckerColor = Color.FromRgba(40, 42, 54, 255), + CheckerColor2 = Color.FromRgba(36, 38, 48, 255), + LinkColor = Color.FromRgba(98, 114, 164, 255), + MenuHighlightColor = Color.FromRgba(36, 38, 48, 255), + MenuHighlightBorderColor = Color.FromRgba(255, 121, 198, 255), + MenuBorderColor = Color.FromRgba(33, 35, 43, 255), + MenuCheckBackgroundColor = Color.FromRgba(45, 47, 61, 255), + SeparatorLightColor = Color.FromRgba(45, 47, 61, 255), + SeparatorDarkColor = Color.FromRgba(33, 35, 43, 255) + }; + + public static List GetDefaultThemes() + { + return [DarkTheme, LightTheme, NightTheme, NordDarkTheme, NordLightTheme, DraculaTheme]; + } + + public override string ToString() + { + return Name; + } } diff --git a/SnapX.Core/Telemetry.cs b/SnapX.Core/Telemetry.cs index bfe79675e..00c481bfb 100644 --- a/SnapX.Core/Telemetry.cs +++ b/SnapX.Core/Telemetry.cs @@ -1,9 +1,9 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; +using System.Text.Json; using System.Text.Json.Serialization; using Aptabase.Core; using Dapper; using Microsoft.Data.Sqlite; +using SnapX.Core.Interfaces; using SnapX.Core.Utils; namespace SnapX.Core; @@ -43,7 +43,7 @@ internal partial class SentryContext : JsonSerializerContext; [JsonSerializable(typeof(OsInfo.GenericGraphicsInfo))] internal partial class AptabaseContext : JsonSerializerContext; -public sealed class Telemetry(SqliteConnection Connection, AptabaseClient AptabaseClient) +public sealed class Telemetry(SqliteConnection Connection, AptabaseClient AptabaseClient, ILoggerService Logger) { [DapperAot] public void LogTelemetry(string provider, string eventName, string envelope) @@ -60,14 +60,11 @@ INSERT INTO TelemetryLog (EventName, Provider, Envelope) } catch (Exception ex) { - // Do not use DebugHelper.WriteException, that will call this function again! - DebugHelper.WriteLine($"Telemetry Logger Error: {ex.Message}"); - DebugHelper.WriteLine(ex.ToString()); + Logger.Error("Telemetry Logger Error: {ExMessage}", ex.ToString()); } }); } - [RequiresUnreferencedCode("Uses reflection to access properties that may be removed by the trimmer.")] public void TrackEvent(string EventName, Dictionary? Envelope = null) { if (string.IsNullOrWhiteSpace(EventName)) return; diff --git a/SnapX.Core/Upload/APIKeys.cs b/SnapX.Core/Upload/APIKeys.cs index 1dc7fbcff..dadbeb57c 100644 --- a/SnapX.Core/Upload/APIKeys.cs +++ b/SnapX.Core/Upload/APIKeys.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/FileUploaderService.cs b/SnapX.Core/Upload/BaseServices/FileUploaderService.cs index c482b71f0..792e09c7a 100644 --- a/SnapX.Core/Upload/BaseServices/FileUploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/FileUploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/IGenericUploaderService.cs b/SnapX.Core/Upload/BaseServices/IGenericUploaderService.cs index 3a35ccfe1..793b16d0d 100644 --- a/SnapX.Core/Upload/BaseServices/IGenericUploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/IGenericUploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/IUploaderService.cs b/SnapX.Core/Upload/BaseServices/IUploaderService.cs index 72bc1f37f..6a315d6de 100644 --- a/SnapX.Core/Upload/BaseServices/IUploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/IUploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/ImageUploaderService.cs b/SnapX.Core/Upload/BaseServices/ImageUploaderService.cs index 2d48d4805..5ce1a44ef 100644 --- a/SnapX.Core/Upload/BaseServices/ImageUploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/ImageUploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/TextUploaderService.cs b/SnapX.Core/Upload/BaseServices/TextUploaderService.cs index b8d3148e8..5d3455e26 100644 --- a/SnapX.Core/Upload/BaseServices/TextUploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/TextUploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/URLSharingService.cs b/SnapX.Core/Upload/BaseServices/URLSharingService.cs index 5715c5733..c7bfe506a 100644 --- a/SnapX.Core/Upload/BaseServices/URLSharingService.cs +++ b/SnapX.Core/Upload/BaseServices/URLSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/URLShortenerService.cs b/SnapX.Core/Upload/BaseServices/URLShortenerService.cs index 2c6e0cb93..f9b5a9212 100644 --- a/SnapX.Core/Upload/BaseServices/URLShortenerService.cs +++ b/SnapX.Core/Upload/BaseServices/URLShortenerService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseServices/UploaderService.cs b/SnapX.Core/Upload/BaseServices/UploaderService.cs index 20c372f0a..12097be24 100644 --- a/SnapX.Core/Upload/BaseServices/UploaderService.cs +++ b/SnapX.Core/Upload/BaseServices/UploaderService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/GenericUploader.cs b/SnapX.Core/Upload/BaseUploaders/GenericUploader.cs index 67535c588..d154505a5 100644 --- a/SnapX.Core/Upload/BaseUploaders/GenericUploader.cs +++ b/SnapX.Core/Upload/BaseUploaders/GenericUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/ImageUploader.cs b/SnapX.Core/Upload/BaseUploaders/ImageUploader.cs index eae6feaf5..a05b02772 100644 --- a/SnapX.Core/Upload/BaseUploaders/ImageUploader.cs +++ b/SnapX.Core/Upload/BaseUploaders/ImageUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/TextUploader.cs b/SnapX.Core/Upload/BaseUploaders/TextUploader.cs index f54adbefe..e586908e6 100644 --- a/SnapX.Core/Upload/BaseUploaders/TextUploader.cs +++ b/SnapX.Core/Upload/BaseUploaders/TextUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/URLSharer.cs b/SnapX.Core/Upload/BaseUploaders/URLSharer.cs index 90205b4f6..a32d1ed45 100644 --- a/SnapX.Core/Upload/BaseUploaders/URLSharer.cs +++ b/SnapX.Core/Upload/BaseUploaders/URLSharer.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/URLShortener.cs b/SnapX.Core/Upload/BaseUploaders/URLShortener.cs index 745c00089..b59ece41f 100644 --- a/SnapX.Core/Upload/BaseUploaders/URLShortener.cs +++ b/SnapX.Core/Upload/BaseUploaders/URLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/BaseUploaders/Uploader.cs b/SnapX.Core/Upload/BaseUploaders/Uploader.cs index 298c32ce7..3035fc010 100644 --- a/SnapX.Core/Upload/BaseUploaders/Uploader.cs +++ b/SnapX.Core/Upload/BaseUploaders/Uploader.cs @@ -1,10 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Collections.Specialized; using System.Net; using System.Text; +using MimeTypeCore; using SnapX.Core.Upload.OAuth; using SnapX.Core.Upload.Utils; using SnapX.Core.Utils; @@ -256,7 +256,7 @@ protected UploadResult SendRequestFileRange(string? url, Stream data, string? fi } contentLength = Math.Min(contentLength, data.Length - contentPosition); - string contentType = MimeTypes.GetMimeType(fileName); + var contentType = MimeTypeMap.GetMimeType(fileName); if (headers == null) { diff --git a/SnapX.Core/Upload/Custom/CustomUploaderInput.cs b/SnapX.Core/Upload/Custom/CustomUploaderInput.cs index f6f23b1a1..648b3ad00 100644 --- a/SnapX.Core/Upload/Custom/CustomUploaderInput.cs +++ b/SnapX.Core/Upload/Custom/CustomUploaderInput.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/CustomUploaderItem.cs b/SnapX.Core/Upload/Custom/CustomUploaderItem.cs index fb4d1de17..da6b046c1 100644 --- a/SnapX.Core/Upload/Custom/CustomUploaderItem.cs +++ b/SnapX.Core/Upload/Custom/CustomUploaderItem.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunction.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunction.cs index 38d573e67..e0ba1792c 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunction.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunction.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionBase64.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionBase64.cs index 0aa624e91..35d702b07 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionBase64.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionBase64.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionFileName.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionFileName.cs index 8a9b486a6..bca367219 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionFileName.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionFileName.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionHeader.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionHeader.cs index a11b2ed31..423109ea4 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionHeader.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionHeader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInput.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInput.cs index dabc7a685..ec4f26a78 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInput.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInput.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInputBox.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInputBox.cs index 8e4fb1ce3..920b0f4fa 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInputBox.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionInputBox.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionJson.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionJson.cs index 105a18147..6bd26d591 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionJson.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionJson.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionOutputBox.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionOutputBox.cs index f1a1f4d54..c136b9d59 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionOutputBox.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionOutputBox.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRandom.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRandom.cs index 7e2c88651..6fd64b676 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRandom.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRandom.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRegex.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRegex.cs index 63718675c..11dbcfb5e 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRegex.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionRegex.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponse.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponse.cs index b8b16f32a..4c4071fe5 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponse.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponse.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponseURL.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponseURL.cs index 40462401c..c9e0944d9 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponseURL.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionResponseURL.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionSelect.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionSelect.cs index 96c783636..82c01ceef 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionSelect.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionSelect.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionXml.cs b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionXml.cs index abe22c9be..2bf1701a5 100644 --- a/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionXml.cs +++ b/SnapX.Core/Upload/Custom/Functions/CustomUploaderFunctionXml.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/ShareXCustomUploaderSyntaxParser.cs b/SnapX.Core/Upload/Custom/ShareXCustomUploaderSyntaxParser.cs index de53c3a9e..dc0100be0 100644 --- a/SnapX.Core/Upload/Custom/ShareXCustomUploaderSyntaxParser.cs +++ b/SnapX.Core/Upload/Custom/ShareXCustomUploaderSyntaxParser.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Custom/ShareXSyntaxParser.cs b/SnapX.Core/Upload/Custom/ShareXSyntaxParser.cs index 7407eaaa9..28a4928a7 100644 --- a/SnapX.Core/Upload/Custom/ShareXSyntaxParser.cs +++ b/SnapX.Core/Upload/Custom/ShareXSyntaxParser.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/AmazonS3.cs b/SnapX.Core/Upload/File/AmazonS3.cs index 4f1c37ecd..2cf82941b 100644 --- a/SnapX.Core/Upload/File/AmazonS3.cs +++ b/SnapX.Core/Upload/File/AmazonS3.cs @@ -1,10 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Collections.Specialized; using System.ComponentModel; using System.Globalization; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Custom; @@ -109,7 +109,7 @@ public override UploadResult Upload(Stream stream, string? fileName) var scope = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request"); var credential = URLHelpers.CombineURL(Settings.AccessKeyID, scope); var timeStamp = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture); - var contentType = MimeTypes.GetMimeType(fileName); + var contentType = MimeTypeMap.GetMimeType(fileName); string hashedPayload; if (Settings.SignedPayload) diff --git a/SnapX.Core/Upload/File/AmazonS3Endpoint.cs b/SnapX.Core/Upload/File/AmazonS3Endpoint.cs index dfb949707..2c1c644aa 100644 --- a/SnapX.Core/Upload/File/AmazonS3Endpoint.cs +++ b/SnapX.Core/Upload/File/AmazonS3Endpoint.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/AmazonS3Settings.cs b/SnapX.Core/Upload/File/AmazonS3Settings.cs index 542a5c442..397778724 100644 --- a/SnapX.Core/Upload/File/AmazonS3Settings.cs +++ b/SnapX.Core/Upload/File/AmazonS3Settings.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/AzureStorage.cs b/SnapX.Core/Upload/File/AzureStorage.cs index e934fc58a..d3f024817 100644 --- a/SnapX.Core/Upload/File/AzureStorage.cs +++ b/SnapX.Core/Upload/File/AzureStorage.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,6 +5,7 @@ using System.Globalization; using System.Security.Cryptography; using System.Text; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Utils; @@ -74,7 +74,7 @@ public override UploadResult Upload(Stream stream, string? fileName) OnEarlyURLCopyRequested(resultURL); - var contentType = MimeTypes.GetMimeType(fileName); + var contentType = MimeTypeMap.GetMimeType(fileName); var requestHeaders = new NameValueCollection { { "x-ms-date", date }, diff --git a/SnapX.Core/Upload/File/BackblazeB2.cs b/SnapX.Core/Upload/File/BackblazeB2.cs index 9ad977fa9..a59e27873 100644 --- a/SnapX.Core/Upload/File/BackblazeB2.cs +++ b/SnapX.Core/Upload/File/BackblazeB2.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -10,6 +9,7 @@ using System.Security.Cryptography; using System.Text; using System.Text.Json; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Utils; @@ -405,7 +405,7 @@ private B2UploadResult B2ApiUploadFile(B2UploadUrl b2UploadUrl, string? destinat ["X-Bz-Info-b2-content-disposition"] = URLHelpers.URLEncode(contentDisposition.ToString()), }; - string contentType = MimeTypes.GetMimeType(destinationPath); + string contentType = MimeTypeMap.GetMimeType(destinationPath); using var response = GetResponse(HttpMethod.Post, b2UploadUrl.uploadUrl, data: file, contentType: contentType, headers: headers, allowNon2xxResponses: true); diff --git a/SnapX.Core/Upload/File/Box.cs b/SnapX.Core/Upload/File/Box.cs index 5bf3a8275..b20a59da5 100644 --- a/SnapX.Core/Upload/File/Box.cs +++ b/SnapX.Core/Upload/File/Box.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Copy.cs b/SnapX.Core/Upload/File/Copy.cs index 495bb9901..dd741dec6 100644 --- a/SnapX.Core/Upload/File/Copy.cs +++ b/SnapX.Core/Upload/File/Copy.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/CustomFileUploader.cs b/SnapX.Core/Upload/File/CustomFileUploader.cs index ffb236698..ebf4dbf28 100644 --- a/SnapX.Core/Upload/File/CustomFileUploader.cs +++ b/SnapX.Core/Upload/File/CustomFileUploader.cs @@ -1,7 +1,7 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Custom; @@ -64,7 +64,7 @@ public override UploadResult Upload(Stream stream, string? fileName) } else if (uploader.Body == CustomUploaderBody.Binary) { - result.Response = SendRequest(uploader.RequestMethod, uploader.GetRequestURL(input), stream, MimeTypes.GetMimeType(fileName), null, + result.Response = SendRequest(uploader.RequestMethod, uploader.GetRequestURL(input), stream, MimeTypeMap.GetMimeType(fileName), null, uploader.GetHeaders(input)); } else diff --git a/SnapX.Core/Upload/File/DropIO.cs b/SnapX.Core/Upload/File/DropIO.cs index d71652814..3c9bafd05 100644 --- a/SnapX.Core/Upload/File/DropIO.cs +++ b/SnapX.Core/Upload/File/DropIO.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Dropbox.cs b/SnapX.Core/Upload/File/Dropbox.cs index e2cf1b641..e55c04dca 100644 --- a/SnapX.Core/Upload/File/Dropbox.cs +++ b/SnapX.Core/Upload/File/Dropbox.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Email.cs b/SnapX.Core/Upload/File/Email.cs index 5bc29c660..43a73b0bc 100644 --- a/SnapX.Core/Upload/File/Email.cs +++ b/SnapX.Core/Upload/File/Email.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/FTP.cs b/SnapX.Core/Upload/File/FTP.cs index 22d022688..5343bc553 100644 --- a/SnapX.Core/Upload/File/FTP.cs +++ b/SnapX.Core/Upload/File/FTP.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/FTPAccount.cs b/SnapX.Core/Upload/File/FTPAccount.cs index e3a8b2fd5..b64867695 100644 --- a/SnapX.Core/Upload/File/FTPAccount.cs +++ b/SnapX.Core/Upload/File/FTPAccount.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/FileBin.cs b/SnapX.Core/Upload/File/FileBin.cs index e78e54fa3..c9abbf8cb 100644 --- a/SnapX.Core/Upload/File/FileBin.cs +++ b/SnapX.Core/Upload/File/FileBin.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/FileSonic.cs b/SnapX.Core/Upload/File/FileSonic.cs index 608df1ac1..64c97fbf8 100644 --- a/SnapX.Core/Upload/File/FileSonic.cs +++ b/SnapX.Core/Upload/File/FileSonic.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/GoogleCloudStorage.cs b/SnapX.Core/Upload/File/GoogleCloudStorage.cs index f1788a488..84bf5733a 100644 --- a/SnapX.Core/Upload/File/GoogleCloudStorage.cs +++ b/SnapX.Core/Upload/File/GoogleCloudStorage.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/GoogleDrive.cs b/SnapX.Core/Upload/File/GoogleDrive.cs index 2ffce4649..72801cf26 100644 --- a/SnapX.Core/Upload/File/GoogleDrive.cs +++ b/SnapX.Core/Upload/File/GoogleDrive.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Hostr.cs b/SnapX.Core/Upload/File/Hostr.cs index 0c0c67b66..0502fdc6e 100644 --- a/SnapX.Core/Upload/File/Hostr.cs +++ b/SnapX.Core/Upload/File/Hostr.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Jira.cs b/SnapX.Core/Upload/File/Jira.cs index e91ab0c3b..cd29a2fea 100644 --- a/SnapX.Core/Upload/File/Jira.cs +++ b/SnapX.Core/Upload/File/Jira.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Lambda.cs b/SnapX.Core/Upload/File/Lambda.cs index 21c5be97a..3255ab245 100644 --- a/SnapX.Core/Upload/File/Lambda.cs +++ b/SnapX.Core/Upload/File/Lambda.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/LobFile.cs b/SnapX.Core/Upload/File/LobFile.cs index 43ecdf632..479eba7c2 100644 --- a/SnapX.Core/Upload/File/LobFile.cs +++ b/SnapX.Core/Upload/File/LobFile.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/LocalhostAccount.cs b/SnapX.Core/Upload/File/LocalhostAccount.cs index 3d3049180..84469cf05 100644 --- a/SnapX.Core/Upload/File/LocalhostAccount.cs +++ b/SnapX.Core/Upload/File/LocalhostAccount.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/MediaFire.cs b/SnapX.Core/Upload/File/MediaFire.cs index 193db5ac5..c2bbdb1fd 100644 --- a/SnapX.Core/Upload/File/MediaFire.cs +++ b/SnapX.Core/Upload/File/MediaFire.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Mega.cs b/SnapX.Core/Upload/File/Mega.cs index 54a051138..0086b85c5 100644 --- a/SnapX.Core/Upload/File/Mega.cs +++ b/SnapX.Core/Upload/File/Mega.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/MegaAuthInfos.cs b/SnapX.Core/Upload/File/MegaAuthInfos.cs index 83094a402..9f473d22c 100644 --- a/SnapX.Core/Upload/File/MegaAuthInfos.cs +++ b/SnapX.Core/Upload/File/MegaAuthInfos.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/OneDrive.cs b/SnapX.Core/Upload/File/OneDrive.cs index b4f5f4d89..64003e3f6 100644 --- a/SnapX.Core/Upload/File/OneDrive.cs +++ b/SnapX.Core/Upload/File/OneDrive.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/OwnCloud.cs b/SnapX.Core/Upload/File/OwnCloud.cs index 34f43bddf..1b920e490 100644 --- a/SnapX.Core/Upload/File/OwnCloud.cs +++ b/SnapX.Core/Upload/File/OwnCloud.cs @@ -1,10 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Utils; @@ -89,7 +89,7 @@ public override UploadResult Upload(Stream stream, string? fileName) var headers = RequestHelpers.CreateAuthenticationHeader(Username, Password); headers["OCS-APIREQUEST"] = "true"; - var response = SendRequest(HttpMethod.Put, url, stream, MimeTypes.GetMimeType(fileName), null, headers); + var response = SendRequest(HttpMethod.Put, url, stream, MimeTypeMap.GetMimeType(fileName), null, headers); var result = new UploadResult(response); diff --git a/SnapX.Core/Upload/File/Plik.cs b/SnapX.Core/Upload/File/Plik.cs index b8820c3ec..6e3533daf 100644 --- a/SnapX.Core/Upload/File/Plik.cs +++ b/SnapX.Core/Upload/File/Plik.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Utils; @@ -54,7 +54,7 @@ public override UploadResult Upload(Stream stream, string? fileName) metaDataReq.Files = new UploadMetadataRequestFile0(); metaDataReq.Files.File0 = new UploadMetadataRequestFile(); metaDataReq.Files.File0.FileName = fileName; - metaDataReq.Files.File0.FileType = MimeTypes.GetMimeType(fileName); + metaDataReq.Files.File0.FileType = MimeTypeMap.GetMimeType(fileName); metaDataReq.Files.File0.FileSize = Convert.ToInt32(stream.Length); metaDataReq.Removable = Settings.Removable; metaDataReq.OneShot = Settings.OneShot; diff --git a/SnapX.Core/Upload/File/PlikSettings.cs b/SnapX.Core/Upload/File/PlikSettings.cs index 304d1d72c..0e8b30fb3 100644 --- a/SnapX.Core/Upload/File/PlikSettings.cs +++ b/SnapX.Core/Upload/File/PlikSettings.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Pomf.cs b/SnapX.Core/Upload/File/Pomf.cs index b040cc5e0..707950052 100644 --- a/SnapX.Core/Upload/File/Pomf.cs +++ b/SnapX.Core/Upload/File/Pomf.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/PomfUploader.cs b/SnapX.Core/Upload/File/PomfUploader.cs index 6b6b851a2..9eff96338 100644 --- a/SnapX.Core/Upload/File/PomfUploader.cs +++ b/SnapX.Core/Upload/File/PomfUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Pushbullet.cs b/SnapX.Core/Upload/File/Pushbullet.cs index 067958d7d..5d2fafa1b 100644 --- a/SnapX.Core/Upload/File/Pushbullet.cs +++ b/SnapX.Core/Upload/File/Pushbullet.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Puush.cs b/SnapX.Core/Upload/File/Puush.cs index a2e233130..f9ba45941 100644 --- a/SnapX.Core/Upload/File/Puush.cs +++ b/SnapX.Core/Upload/File/Puush.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/SFTP.cs b/SnapX.Core/Upload/File/SFTP.cs index 60d06ee76..f186c035a 100644 --- a/SnapX.Core/Upload/File/SFTP.cs +++ b/SnapX.Core/Upload/File/SFTP.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Seafile.cs b/SnapX.Core/Upload/File/Seafile.cs index 369f78bcc..074dc4fc4 100644 --- a/SnapX.Core/Upload/File/Seafile.cs +++ b/SnapX.Core/Upload/File/Seafile.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/SendSpace.cs b/SnapX.Core/Upload/File/SendSpace.cs index ecdedc38b..35ab45537 100644 --- a/SnapX.Core/Upload/File/SendSpace.cs +++ b/SnapX.Core/Upload/File/SendSpace.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/SendSpaceManager.cs b/SnapX.Core/Upload/File/SendSpaceManager.cs index f2aef5936..4d577b2f5 100644 --- a/SnapX.Core/Upload/File/SendSpaceManager.cs +++ b/SnapX.Core/Upload/File/SendSpaceManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/ShareCX.cs b/SnapX.Core/Upload/File/ShareCX.cs index 5f6a13f6e..78f1b704d 100644 --- a/SnapX.Core/Upload/File/ShareCX.cs +++ b/SnapX.Core/Upload/File/ShareCX.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/SharedFolderUploader.cs b/SnapX.Core/Upload/File/SharedFolderUploader.cs index cef89855c..024e77cdd 100644 --- a/SnapX.Core/Upload/File/SharedFolderUploader.cs +++ b/SnapX.Core/Upload/File/SharedFolderUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Streamable.cs b/SnapX.Core/Upload/File/Streamable.cs index 5230ac86f..0e9d636b8 100644 --- a/SnapX.Core/Upload/File/Streamable.cs +++ b/SnapX.Core/Upload/File/Streamable.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Sul.cs b/SnapX.Core/Upload/File/Sul.cs index 4f38a675c..2d996dfe9 100644 --- a/SnapX.Core/Upload/File/Sul.cs +++ b/SnapX.Core/Upload/File/Sul.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Transfersh.cs b/SnapX.Core/Upload/File/Transfersh.cs index 5301aa842..b21dade6f 100644 --- a/SnapX.Core/Upload/File/Transfersh.cs +++ b/SnapX.Core/Upload/File/Transfersh.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Uguu.cs b/SnapX.Core/Upload/File/Uguu.cs index baa4e1197..4159c78de 100644 --- a/SnapX.Core/Upload/File/Uguu.cs +++ b/SnapX.Core/Upload/File/Uguu.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/Vault_ooo.cs b/SnapX.Core/Upload/File/Vault_ooo.cs index d859bde4e..e977dafa5 100644 --- a/SnapX.Core/Upload/File/Vault_ooo.cs +++ b/SnapX.Core/Upload/File/Vault_ooo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/File/YouTube.cs b/SnapX.Core/Upload/File/YouTube.cs index d8411095f..b60909903 100644 --- a/SnapX.Core/Upload/File/YouTube.cs +++ b/SnapX.Core/Upload/File/YouTube.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/Chevereto.cs b/SnapX.Core/Upload/Img/Chevereto.cs index fc51fce04..eed164a20 100644 --- a/SnapX.Core/Upload/Img/Chevereto.cs +++ b/SnapX.Core/Upload/Img/Chevereto.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/CheveretoUploader.cs b/SnapX.Core/Upload/Img/CheveretoUploader.cs index 962325fb0..67e65145d 100644 --- a/SnapX.Core/Upload/Img/CheveretoUploader.cs +++ b/SnapX.Core/Upload/Img/CheveretoUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/CustomImageUploader.cs b/SnapX.Core/Upload/Img/CustomImageUploader.cs index 959de309e..052baa64b 100644 --- a/SnapX.Core/Upload/Img/CustomImageUploader.cs +++ b/SnapX.Core/Upload/Img/CustomImageUploader.cs @@ -1,7 +1,7 @@ - // SPDX-License-Identifier: GPL-3.0-or-later +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Custom; @@ -57,7 +57,7 @@ public override UploadResult Upload(Stream stream, string? fileName) } else if (uploader.Body == CustomUploaderBody.Binary) { - ur.Response = SendRequest(uploader.RequestMethod, uploader.GetRequestURL(input), stream, MimeTypes.GetMimeType(fileName), + ur.Response = SendRequest(uploader.RequestMethod, uploader.GetRequestURL(input), stream, MimeTypeMap.GetMimeType(fileName), null, uploader.GetHeaders(input)); } else diff --git a/SnapX.Core/Upload/Img/FlickrUploader.cs b/SnapX.Core/Upload/Img/FlickrUploader.cs index c755e8266..a860f2530 100644 --- a/SnapX.Core/Upload/Img/FlickrUploader.cs +++ b/SnapX.Core/Upload/Img/FlickrUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/ImageBin.cs b/SnapX.Core/Upload/Img/ImageBin.cs index 3192fabf5..62f042d99 100644 --- a/SnapX.Core/Upload/Img/ImageBin.cs +++ b/SnapX.Core/Upload/Img/ImageBin.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/ImageShackUploader.cs b/SnapX.Core/Upload/Img/ImageShackUploader.cs index 19e94029a..7f4a31164 100644 --- a/SnapX.Core/Upload/Img/ImageShackUploader.cs +++ b/SnapX.Core/Upload/Img/ImageShackUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/Img1Uploader.cs b/SnapX.Core/Upload/Img/Img1Uploader.cs index 7f05556b2..1aa73cd9c 100644 --- a/SnapX.Core/Upload/Img/Img1Uploader.cs +++ b/SnapX.Core/Upload/Img/Img1Uploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/Imgur.cs b/SnapX.Core/Upload/Img/Imgur.cs index 591e6d5ec..c2db2f0c6 100644 --- a/SnapX.Core/Upload/Img/Imgur.cs +++ b/SnapX.Core/Upload/Img/Imgur.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/ImmioUploader.cs b/SnapX.Core/Upload/Img/ImmioUploader.cs index 42b8ed383..86b62981b 100644 --- a/SnapX.Core/Upload/Img/ImmioUploader.cs +++ b/SnapX.Core/Upload/Img/ImmioUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/Photobucket.cs b/SnapX.Core/Upload/Img/Photobucket.cs index f48014f7a..5762a8b55 100644 --- a/SnapX.Core/Upload/Img/Photobucket.cs +++ b/SnapX.Core/Upload/Img/Photobucket.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/TwitPicUploader.cs b/SnapX.Core/Upload/Img/TwitPicUploader.cs index 1b0431aa0..065e72653 100644 --- a/SnapX.Core/Upload/Img/TwitPicUploader.cs +++ b/SnapX.Core/Upload/Img/TwitPicUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/TwitSnapsUploader.cs b/SnapX.Core/Upload/Img/TwitSnapsUploader.cs index c3060a06e..eba820e64 100644 --- a/SnapX.Core/Upload/Img/TwitSnapsUploader.cs +++ b/SnapX.Core/Upload/Img/TwitSnapsUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/Twitter.cs b/SnapX.Core/Upload/Img/Twitter.cs index b4978bfe7..affbc70ed 100644 --- a/SnapX.Core/Upload/Img/Twitter.cs +++ b/SnapX.Core/Upload/Img/Twitter.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/UploadScreenshot.cs b/SnapX.Core/Upload/Img/UploadScreenshot.cs index 29047cae8..7ac985524 100644 --- a/SnapX.Core/Upload/Img/UploadScreenshot.cs +++ b/SnapX.Core/Upload/Img/UploadScreenshot.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/VgymeUploader.cs b/SnapX.Core/Upload/Img/VgymeUploader.cs index cd4ca8ef4..5d77f0c9e 100644 --- a/SnapX.Core/Upload/Img/VgymeUploader.cs +++ b/SnapX.Core/Upload/Img/VgymeUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Img/YfrogUploader.cs b/SnapX.Core/Upload/Img/YfrogUploader.cs index 5231821b5..09db7f885 100644 --- a/SnapX.Core/Upload/Img/YfrogUploader.cs +++ b/SnapX.Core/Upload/Img/YfrogUploader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/GoogleOAuth2.cs b/SnapX.Core/Upload/OAuth/GoogleOAuth2.cs index b3af891eb..413a3cfbc 100644 --- a/SnapX.Core/Upload/OAuth/GoogleOAuth2.cs +++ b/SnapX.Core/Upload/OAuth/GoogleOAuth2.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/IOAuth.cs b/SnapX.Core/Upload/OAuth/IOAuth.cs index caf0996e8..be7d71422 100644 --- a/SnapX.Core/Upload/OAuth/IOAuth.cs +++ b/SnapX.Core/Upload/OAuth/IOAuth.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/IOAuth2.cs b/SnapX.Core/Upload/OAuth/IOAuth2.cs index 40f9d9423..e419f23dc 100644 --- a/SnapX.Core/Upload/OAuth/IOAuth2.cs +++ b/SnapX.Core/Upload/OAuth/IOAuth2.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/IOAuth2Basic.cs b/SnapX.Core/Upload/OAuth/IOAuth2Basic.cs index e1f27f4a0..73aa121dd 100644 --- a/SnapX.Core/Upload/OAuth/IOAuth2Basic.cs +++ b/SnapX.Core/Upload/OAuth/IOAuth2Basic.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/IOAuthBase.cs b/SnapX.Core/Upload/OAuth/IOAuthBase.cs index 1bd0a3bb0..91ca502e8 100644 --- a/SnapX.Core/Upload/OAuth/IOAuthBase.cs +++ b/SnapX.Core/Upload/OAuth/IOAuthBase.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/IOauth2Loopback.cs b/SnapX.Core/Upload/OAuth/IOauth2Loopback.cs index 81a421d7b..223479434 100644 --- a/SnapX.Core/Upload/OAuth/IOauth2Loopback.cs +++ b/SnapX.Core/Upload/OAuth/IOauth2Loopback.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuth2Info.cs b/SnapX.Core/Upload/OAuth/OAuth2Info.cs index d1e3eadef..1fd8a1ea0 100644 --- a/SnapX.Core/Upload/OAuth/OAuth2Info.cs +++ b/SnapX.Core/Upload/OAuth/OAuth2Info.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuth2ProofKey.cs b/SnapX.Core/Upload/OAuth/OAuth2ProofKey.cs index 7e01fe9d6..7592f2af4 100644 --- a/SnapX.Core/Upload/OAuth/OAuth2ProofKey.cs +++ b/SnapX.Core/Upload/OAuth/OAuth2ProofKey.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuth2Token.cs b/SnapX.Core/Upload/OAuth/OAuth2Token.cs index 318a021c4..6bf27b9d1 100644 --- a/SnapX.Core/Upload/OAuth/OAuth2Token.cs +++ b/SnapX.Core/Upload/OAuth/OAuth2Token.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuthInfo.cs b/SnapX.Core/Upload/OAuth/OAuthInfo.cs index e872a3656..3b824e88e 100644 --- a/SnapX.Core/Upload/OAuth/OAuthInfo.cs +++ b/SnapX.Core/Upload/OAuth/OAuthInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuthListener.cs b/SnapX.Core/Upload/OAuth/OAuthListener.cs index 265b3e433..65a57fcc5 100644 --- a/SnapX.Core/Upload/OAuth/OAuthListener.cs +++ b/SnapX.Core/Upload/OAuth/OAuthListener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuthManager.cs b/SnapX.Core/Upload/OAuth/OAuthManager.cs index bc13ead7b..8fbb66375 100644 --- a/SnapX.Core/Upload/OAuth/OAuthManager.cs +++ b/SnapX.Core/Upload/OAuth/OAuthManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/OAuth/OAuthUserInfo.cs b/SnapX.Core/Upload/OAuth/OAuthUserInfo.cs index 10f1246f4..c4d5a07ef 100644 --- a/SnapX.Core/Upload/OAuth/OAuthUserInfo.cs +++ b/SnapX.Core/Upload/OAuth/OAuthUserInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/BingVisualSearchSharingService.cs b/SnapX.Core/Upload/SharingServices/BingVisualSearchSharingService.cs index 01d4cd2cf..e67882fb9 100644 --- a/SnapX.Core/Upload/SharingServices/BingVisualSearchSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/BingVisualSearchSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/CustomURLSharingService.cs b/SnapX.Core/Upload/SharingServices/CustomURLSharingService.cs index 84bbaa955..bf650a936 100644 --- a/SnapX.Core/Upload/SharingServices/CustomURLSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/CustomURLSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/DeliciousSharingService.cs b/SnapX.Core/Upload/SharingServices/DeliciousSharingService.cs index 415831fa8..ec7222cf8 100644 --- a/SnapX.Core/Upload/SharingServices/DeliciousSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/DeliciousSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/EmailSharingService.cs b/SnapX.Core/Upload/SharingServices/EmailSharingService.cs index 0155073a0..99b106bc5 100644 --- a/SnapX.Core/Upload/SharingServices/EmailSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/EmailSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/FacebookSharingService.cs b/SnapX.Core/Upload/SharingServices/FacebookSharingService.cs index f4a58be39..6637ce52e 100644 --- a/SnapX.Core/Upload/SharingServices/FacebookSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/FacebookSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/GoogleLensSharingService.cs b/SnapX.Core/Upload/SharingServices/GoogleLensSharingService.cs index 80bcc8a73..b0580693c 100644 --- a/SnapX.Core/Upload/SharingServices/GoogleLensSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/GoogleLensSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/LinkedInSharingService.cs b/SnapX.Core/Upload/SharingServices/LinkedInSharingService.cs index 43d268393..636ab1d37 100644 --- a/SnapX.Core/Upload/SharingServices/LinkedInSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/LinkedInSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/PinterestSharingService.cs b/SnapX.Core/Upload/SharingServices/PinterestSharingService.cs index 7e1a0aebe..11bd50235 100644 --- a/SnapX.Core/Upload/SharingServices/PinterestSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/PinterestSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/PushbulletSharingService.cs b/SnapX.Core/Upload/SharingServices/PushbulletSharingService.cs index 040e6c752..48b64e9ff 100644 --- a/SnapX.Core/Upload/SharingServices/PushbulletSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/PushbulletSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/RedditSharingService.cs b/SnapX.Core/Upload/SharingServices/RedditSharingService.cs index ec20c0989..5c774a622 100644 --- a/SnapX.Core/Upload/SharingServices/RedditSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/RedditSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/SimpleURLSharingService.cs b/SnapX.Core/Upload/SharingServices/SimpleURLSharingService.cs index 7f93bf687..553e2f6ae 100644 --- a/SnapX.Core/Upload/SharingServices/SimpleURLSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/SimpleURLSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/StumbleUponSharingService.cs b/SnapX.Core/Upload/SharingServices/StumbleUponSharingService.cs index f33f98d10..fbc5175a0 100644 --- a/SnapX.Core/Upload/SharingServices/StumbleUponSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/StumbleUponSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/TumblrSharingService.cs b/SnapX.Core/Upload/SharingServices/TumblrSharingService.cs index a6ca77256..43f5557ca 100644 --- a/SnapX.Core/Upload/SharingServices/TumblrSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/TumblrSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/TwitterSharingService.cs b/SnapX.Core/Upload/SharingServices/TwitterSharingService.cs index 3f572e628..cd56c2cd8 100644 --- a/SnapX.Core/Upload/SharingServices/TwitterSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/TwitterSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/SharingServices/VkSharingService.cs b/SnapX.Core/Upload/SharingServices/VkSharingService.cs index b666d2477..3c757b4d8 100644 --- a/SnapX.Core/Upload/SharingServices/VkSharingService.cs +++ b/SnapX.Core/Upload/SharingServices/VkSharingService.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/CustomTextUploader.cs b/SnapX.Core/Upload/Text/CustomTextUploader.cs index 69cc5b50e..e3f3b39cd 100644 --- a/SnapX.Core/Upload/Text/CustomTextUploader.cs +++ b/SnapX.Core/Upload/Text/CustomTextUploader.cs @@ -1,8 +1,8 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Text; +using MimeTypeCore; using SnapX.Core.Upload.BaseServices; using SnapX.Core.Upload.BaseUploaders; using SnapX.Core.Upload.Custom; @@ -123,7 +123,7 @@ public override UploadResult UploadText(string? text, string? fileName) uploader.RequestMethod, uploader.GetRequestURL(input), binaryStream, - MimeTypes.GetMimeType(fileName), + MimeTypeMap.GetMimeType(fileName), null, uploader.GetHeaders(input) ); diff --git a/SnapX.Core/Upload/Text/GitHubGist.cs b/SnapX.Core/Upload/Text/GitHubGist.cs index 44fd40eb4..69851caed 100644 --- a/SnapX.Core/Upload/Text/GitHubGist.cs +++ b/SnapX.Core/Upload/Text/GitHubGist.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Hastebin.cs b/SnapX.Core/Upload/Text/Hastebin.cs index 0a41b3591..e1bfc467c 100644 --- a/SnapX.Core/Upload/Text/Hastebin.cs +++ b/SnapX.Core/Upload/Text/Hastebin.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/OneTimeSecret.cs b/SnapX.Core/Upload/Text/OneTimeSecret.cs index f67d65b3c..db0c9fece 100644 --- a/SnapX.Core/Upload/Text/OneTimeSecret.cs +++ b/SnapX.Core/Upload/Text/OneTimeSecret.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Paste2.cs b/SnapX.Core/Upload/Text/Paste2.cs index a621c8ab1..84aeadaac 100644 --- a/SnapX.Core/Upload/Text/Paste2.cs +++ b/SnapX.Core/Upload/Text/Paste2.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Paste_ee.cs b/SnapX.Core/Upload/Text/Paste_ee.cs index 3ec4eef7f..6c3b749c9 100644 --- a/SnapX.Core/Upload/Text/Paste_ee.cs +++ b/SnapX.Core/Upload/Text/Paste_ee.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Pastebin.cs b/SnapX.Core/Upload/Text/Pastebin.cs index df5f8b175..38973a515 100644 --- a/SnapX.Core/Upload/Text/Pastebin.cs +++ b/SnapX.Core/Upload/Text/Pastebin.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Pastebin_ca.cs b/SnapX.Core/Upload/Text/Pastebin_ca.cs index f0af2c3e8..91ed4a5ce 100644 --- a/SnapX.Core/Upload/Text/Pastebin_ca.cs +++ b/SnapX.Core/Upload/Text/Pastebin_ca.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Pastie.cs b/SnapX.Core/Upload/Text/Pastie.cs index b7638dacc..cd06fd7f2 100644 --- a/SnapX.Core/Upload/Text/Pastie.cs +++ b/SnapX.Core/Upload/Text/Pastie.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Slexy.cs b/SnapX.Core/Upload/Text/Slexy.cs index 33481740c..a26074dc5 100644 --- a/SnapX.Core/Upload/Text/Slexy.cs +++ b/SnapX.Core/Upload/Text/Slexy.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Text/Upaste.cs b/SnapX.Core/Upload/Text/Upaste.cs index 2dcb3e8bb..6199c9110 100644 --- a/SnapX.Core/Upload/Text/Upaste.cs +++ b/SnapX.Core/Upload/Text/Upaste.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/BitlyURLShortener.cs b/SnapX.Core/Upload/URL/BitlyURLShortener.cs index e176b4233..b92bf0fa3 100644 --- a/SnapX.Core/Upload/URL/BitlyURLShortener.cs +++ b/SnapX.Core/Upload/URL/BitlyURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/CustomURLShortener.cs b/SnapX.Core/Upload/URL/CustomURLShortener.cs index 5e5755cc0..d2a1b1fdf 100644 --- a/SnapX.Core/Upload/URL/CustomURLShortener.cs +++ b/SnapX.Core/Upload/URL/CustomURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/FirebaseDynamicLinksURLShortener.cs b/SnapX.Core/Upload/URL/FirebaseDynamicLinksURLShortener.cs index dcacb1eb4..201b107dd 100644 --- a/SnapX.Core/Upload/URL/FirebaseDynamicLinksURLShortener.cs +++ b/SnapX.Core/Upload/URL/FirebaseDynamicLinksURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/IsgdURLShortener.cs b/SnapX.Core/Upload/URL/IsgdURLShortener.cs index a76e5a884..f0c3719ac 100644 --- a/SnapX.Core/Upload/URL/IsgdURLShortener.cs +++ b/SnapX.Core/Upload/URL/IsgdURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/KuttURLShortener.cs b/SnapX.Core/Upload/URL/KuttURLShortener.cs index 58cb636d8..2a0cbcfc8 100644 --- a/SnapX.Core/Upload/URL/KuttURLShortener.cs +++ b/SnapX.Core/Upload/URL/KuttURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/NlcmURLShortener.cs b/SnapX.Core/Upload/URL/NlcmURLShortener.cs index 36e0ef190..94747ebe3 100644 --- a/SnapX.Core/Upload/URL/NlcmURLShortener.cs +++ b/SnapX.Core/Upload/URL/NlcmURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/PolrURLShortener.cs b/SnapX.Core/Upload/URL/PolrURLShortener.cs index b83be2f43..1fb928129 100644 --- a/SnapX.Core/Upload/URL/PolrURLShortener.cs +++ b/SnapX.Core/Upload/URL/PolrURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/QRnetURLShortener.cs b/SnapX.Core/Upload/URL/QRnetURLShortener.cs index 020c24d9b..4ec537265 100644 --- a/SnapX.Core/Upload/URL/QRnetURLShortener.cs +++ b/SnapX.Core/Upload/URL/QRnetURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/TinyURLShortener.cs b/SnapX.Core/Upload/URL/TinyURLShortener.cs index 20338434a..b094e38c8 100644 --- a/SnapX.Core/Upload/URL/TinyURLShortener.cs +++ b/SnapX.Core/Upload/URL/TinyURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/TurlURLShortener.cs b/SnapX.Core/Upload/URL/TurlURLShortener.cs index a8c2df575..240b5021f 100644 --- a/SnapX.Core/Upload/URL/TurlURLShortener.cs +++ b/SnapX.Core/Upload/URL/TurlURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/TwoGPURLShortener.cs b/SnapX.Core/Upload/URL/TwoGPURLShortener.cs index a971d5b9f..4077e3136 100644 --- a/SnapX.Core/Upload/URL/TwoGPURLShortener.cs +++ b/SnapX.Core/Upload/URL/TwoGPURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/VURLShortener.cs b/SnapX.Core/Upload/URL/VURLShortener.cs index 72fee0c7c..c92b2dac3 100644 --- a/SnapX.Core/Upload/URL/VURLShortener.cs +++ b/SnapX.Core/Upload/URL/VURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/VgdURLShortener.cs b/SnapX.Core/Upload/URL/VgdURLShortener.cs index 19339f5bf..884d54a77 100644 --- a/SnapX.Core/Upload/URL/VgdURLShortener.cs +++ b/SnapX.Core/Upload/URL/VgdURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/YourlsURLShortener.cs b/SnapX.Core/Upload/URL/YourlsURLShortener.cs index 235d74247..d9d0fcb40 100644 --- a/SnapX.Core/Upload/URL/YourlsURLShortener.cs +++ b/SnapX.Core/Upload/URL/YourlsURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/URL/ZeroWidthURLShortener.cs b/SnapX.Core/Upload/URL/ZeroWidthURLShortener.cs index e1f04e9a7..887e18aa1 100644 --- a/SnapX.Core/Upload/URL/ZeroWidthURLShortener.cs +++ b/SnapX.Core/Upload/URL/ZeroWidthURLShortener.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadInfoManager.cs b/SnapX.Core/Upload/UploadInfoManager.cs index 7b766caba..0da68edca 100644 --- a/SnapX.Core/Upload/UploadInfoManager.cs +++ b/SnapX.Core/Upload/UploadInfoManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadInfoParser.cs b/SnapX.Core/Upload/UploadInfoParser.cs index 616e489f2..2228cd775 100644 --- a/SnapX.Core/Upload/UploadInfoParser.cs +++ b/SnapX.Core/Upload/UploadInfoParser.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadInfoStatus.cs b/SnapX.Core/Upload/UploadInfoStatus.cs index d4d1c5659..c40227bc8 100644 --- a/SnapX.Core/Upload/UploadInfoStatus.cs +++ b/SnapX.Core/Upload/UploadInfoStatus.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadManager.cs b/SnapX.Core/Upload/UploadManager.cs index 69f10251c..51383d518 100644 --- a/SnapX.Core/Upload/UploadManager.cs +++ b/SnapX.Core/Upload/UploadManager.cs @@ -1,11 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Runtime.InteropServices; using System.Web; using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; +using SnapX.Core.Interfaces; using SnapX.Core.Job; using SnapX.Core.Utils; using SnapX.Core.Utils.Extensions; @@ -14,11 +13,17 @@ namespace SnapX.Core.Upload; -public static class UploadManager +public class UploadManager { + private static IFilePicker _filePicker; + + public UploadManager(IFilePicker filePicker) + { + _filePicker = filePicker; + } public static void UploadFile(string? filePath, TaskSettings? taskSettings = null) { - if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); if (!string.IsNullOrEmpty(filePath)) { @@ -72,16 +77,25 @@ private static bool IsUploadConfirmed(int length) public static void UploadFile(TaskSettings? taskSettings = null) { taskSettings ??= TaskSettings.GetDefaultTaskSettings(); - var data = new NeedFileOpenerEvent() - { - Title = Lang.UploadManagerUploadFile, - Multiselect = true, - Directory = IsValidDirectory(SnapX.Settings.FileUploadDefaultDirectory) ? SnapX.Settings.FileUploadDefaultDirectory : UserDirectory.DesktopDir, - TaskSettings = taskSettings - }; + var title = Lang.UploadManagerUploadFile; + var initialDir = IsValidDirectory(SnapX.Settings.FileUploadDefaultDirectory) + ? SnapX.Settings.FileUploadDefaultDirectory + : UserDirectory.DesktopDir; + DebugHelper.WriteLine("Need file to upload. Asking UI for file."); - // The UI will now do the rest. - SnapX.EventAggregator.Publish(data); + var selectedFiles = _filePicker.PickFilesAsync( + title, + initialDir, + allowMultiple: true).GetAwaiter().GetResult(); + + if (selectedFiles.Length == 0) + { + DebugHelper.WriteLine("User cancelled file picker."); + return; + } + + DebugHelper.WriteLine($"User selected {selectedFiles.Length} file(s) to upload."); + UploadFile(selectedFiles); } public static bool IsValidDirectory(string? dir) @@ -89,7 +103,7 @@ public static bool IsValidDirectory(string? dir) return !string.IsNullOrEmpty(dir) && Directory.Exists(dir); } - public static void UploadFolder(TaskSettings taskSettings = null) + public static void UploadFolder(TaskSettings? taskSettings = null) { // using (FolderSelectDialog folderDialog = new FolderSelectDialog()) // { @@ -112,7 +126,7 @@ public static void UploadFolder(TaskSettings taskSettings = null) // } } - public static void ProcessImageUpload(Image image, TaskSettings taskSettings) + public static void ProcessImageUpload(Image image, TaskSettings? taskSettings) { if (image != null) { @@ -125,7 +139,7 @@ public static void ProcessImageUpload(Image image, TaskSettings taskSettings) } } - public static void ProcessTextUpload(string? text, TaskSettings taskSettings) + public static void ProcessTextUpload(string? text, TaskSettings? taskSettings) { if (string.IsNullOrEmpty(text)) return; @@ -163,7 +177,7 @@ public static void ProcessTextUpload(string? text, TaskSettings taskSettings) } } - public static void ProcessFilesUpload(string?[] files, TaskSettings taskSettings) + public static void ProcessFilesUpload(string?[] files, TaskSettings? taskSettings) { if (files?.Length > 0) { @@ -172,19 +186,15 @@ public static void ProcessFilesUpload(string?[] files, TaskSettings taskSettings } - public static void ClipboardUpload(TaskSettings taskSettings = null) + public static void ClipboardUpload(TaskSettings? taskSettings = null) { - if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); try { if (Clipboard.ContainsImage()) { - Image image; - - - image = Clipboard.GetImage(); - + var image = Clipboard.GetImage(); ProcessImageUpload(image, taskSettings); } @@ -214,9 +224,9 @@ public static void ClipboardUpload(TaskSettings taskSettings = null) } } - public static void UploadURL(TaskSettings taskSettings = null, string? url = null) + public static void UploadURL(TaskSettings? taskSettings = null, string? url = null) { - if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); string? inputText = null; @@ -233,22 +243,22 @@ public static void UploadURL(TaskSettings taskSettings = null, string? url = nul DownloadAndUploadFile(url, taskSettings); } } - public static void RunImageTask(Image image, TaskSettings taskSettings) + public static void RunImageTask(Image image, TaskSettings? taskSettings) { var metadata = new TaskMetadata(image); RunImageTask(metadata, taskSettings); } - public static void RunImageTask(Image image, TaskSettings taskSettings, bool skipQuickTaskMenu = false, bool skipAfterCaptureWindow = false) + public static void RunImageTask(Image image, TaskSettings? taskSettings, bool skipQuickTaskMenu = false, bool skipAfterCaptureWindow = false) { var metadata = new TaskMetadata(image); RunImageTask(metadata, taskSettings, skipQuickTaskMenu, skipAfterCaptureWindow); } - public static void RunImageTask(TaskMetadata metadata, TaskSettings taskSettings, bool skipQuickTaskMenu = false, bool skipAfterCaptureWindow = false) + public static void RunImageTask(TaskMetadata metadata, TaskSettings? taskSettings, bool skipQuickTaskMenu = false, bool skipAfterCaptureWindow = false) { - if (taskSettings == null) taskSettings = TaskSettings.GetDefaultTaskSettings(); + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); - if (metadata != null && metadata.Image != null && taskSettings != null) + if (metadata is { Image: not null } && taskSettings != null) { if (!skipQuickTaskMenu && taskSettings.AfterCaptureJob.HasFlag(AfterCaptureTasks.ShowQuickTaskMenu)) { @@ -264,45 +274,34 @@ public static void RunImageTask(TaskMetadata metadata, TaskSettings taskSettings } } - public static void UploadImage(Image image, TaskSettings taskSettings = null) + public static void UploadImage(Image? image, TaskSettings? taskSettings = null) { - if (image != null) + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); + if (image == null) return; + if (taskSettings is { IsSafeTaskSettings: true }) { - if (taskSettings == null) - { - taskSettings = TaskSettings.GetDefaultTaskSettings(); - } - - if (taskSettings.IsSafeTaskSettings) - { - taskSettings.UseDefaultAfterCaptureJob = false; - taskSettings.AfterCaptureJob = AfterCaptureTasks.UploadImageToHost; - } - - RunImageTask(image, taskSettings); + taskSettings.UseDefaultAfterCaptureJob = false; + taskSettings.AfterCaptureJob = AfterCaptureTasks.UploadImageToHost; } + + RunImageTask(image, taskSettings); } - public static void UploadImage(Image image, ImageDestination imageDestination, FileDestination imageFileDestination, TaskSettings taskSettings = null) + public static void UploadImage(Image? image, ImageDestination imageDestination, FileDestination imageFileDestination, TaskSettings? taskSettings = null) { - if (image != null) - { - if (taskSettings == null) - { - taskSettings = TaskSettings.GetDefaultTaskSettings(); - } - - if (taskSettings.IsSafeTaskSettings) - { - taskSettings.UseDefaultAfterCaptureJob = false; - taskSettings.AfterCaptureJob = AfterCaptureTasks.UploadImageToHost; - taskSettings.UseDefaultDestinations = false; - taskSettings.ImageDestination = imageDestination; - taskSettings.ImageFileDestination = imageFileDestination; - } + if (image == null) return; + taskSettings ??= TaskSettings.GetDefaultTaskSettings(); - RunImageTask(image, taskSettings); + if (taskSettings is { IsSafeTaskSettings: true }) + { + taskSettings.UseDefaultAfterCaptureJob = false; + taskSettings.AfterCaptureJob = AfterCaptureTasks.UploadImageToHost; + taskSettings.UseDefaultDestinations = false; + taskSettings.ImageDestination = imageDestination; + taskSettings.ImageFileDestination = imageFileDestination; } + + RunImageTask(image, taskSettings); } public static void UploadText(string? text, TaskSettings? taskSettings = null, bool allowCustomText = false) { @@ -312,11 +311,11 @@ public static void UploadText(string? text, TaskSettings? taskSettings = null, b if (allowCustomText) { - string input = taskSettings.AdvancedSettings.TextCustom; + var input = taskSettings?.AdvancedSettings.TextCustom; if (!string.IsNullOrEmpty(input)) { - if (taskSettings.AdvancedSettings.TextCustomEncodeInput) + if (taskSettings is { AdvancedSettings.TextCustomEncodeInput: true }) { text = HttpUtility.HtmlEncode(text); } @@ -329,7 +328,7 @@ public static void UploadText(string? text, TaskSettings? taskSettings = null, b TaskManager.Start(task); } - public static void UploadImageStream(Stream stream, string? fileName, TaskSettings taskSettings = null) + public static void UploadImageStream(Stream? stream, string? fileName, TaskSettings? taskSettings = null) { taskSettings ??= TaskSettings.GetDefaultTaskSettings(); @@ -341,7 +340,7 @@ public static void UploadImageStream(Stream stream, string? fileName, TaskSettin } - public static void ShortenURL(string? url, TaskSettings taskSettings = null) + public static void ShortenURL(string? url, TaskSettings? taskSettings = null) { if (string.IsNullOrEmpty(url)) return; @@ -365,7 +364,7 @@ public static void ShortenURL(string? url, UrlShortenerType urlShortener) } - public static void ShareURL(string? url, TaskSettings taskSettings = null) + public static void ShareURL(string? url, TaskSettings? taskSettings = null) { if (string.IsNullOrEmpty(url)) return; @@ -389,10 +388,10 @@ public static void ShareURL(string? url, URLSharingServices urlSharingService) TaskManager.Start(task); } - public static void DownloadFile(string? url, TaskSettings taskSettings = null) + public static void DownloadFile(string? url, TaskSettings? taskSettings = null) => DownloadFile(url, false, taskSettings); - public static void DownloadAndUploadFile(string? url, TaskSettings taskSettings = null) + public static void DownloadAndUploadFile(string? url, TaskSettings? taskSettings = null) => DownloadFile(url, true, taskSettings); private static void DownloadFile(string? url, bool upload, TaskSettings? taskSettings = null) diff --git a/SnapX.Core/Upload/UploadResult.cs b/SnapX.Core/Upload/UploadResult.cs index 396d1338a..521649e68 100644 --- a/SnapX.Core/Upload/UploadResult.cs +++ b/SnapX.Core/Upload/UploadResult.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploaderFactory.cs b/SnapX.Core/Upload/UploaderFactory.cs index bc8d5c36c..5c4e11887 100644 --- a/SnapX.Core/Upload/UploaderFactory.cs +++ b/SnapX.Core/Upload/UploaderFactory.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploaderFilter.cs b/SnapX.Core/Upload/UploaderFilter.cs index e20ecbc49..e3df00784 100644 --- a/SnapX.Core/Upload/UploaderFilter.cs +++ b/SnapX.Core/Upload/UploaderFilter.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadersConfig.cs b/SnapX.Core/Upload/UploadersConfig.cs index f5b8ad24d..727fd330f 100644 --- a/SnapX.Core/Upload/UploadersConfig.cs +++ b/SnapX.Core/Upload/UploadersConfig.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/UploadersConfigValidator.cs b/SnapX.Core/Upload/UploadersConfigValidator.cs index c43dd5630..5a24b92d7 100644 --- a/SnapX.Core/Upload/UploadersConfigValidator.cs +++ b/SnapX.Core/Upload/UploadersConfigValidator.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Utils/AccountInfo.cs b/SnapX.Core/Upload/Utils/AccountInfo.cs index b53a303ef..1ba50a7fb 100644 --- a/SnapX.Core/Upload/Utils/AccountInfo.cs +++ b/SnapX.Core/Upload/Utils/AccountInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Utils/Argument.cs b/SnapX.Core/Upload/Utils/Argument.cs index ff7f1b94a..6518e3cf8 100644 --- a/SnapX.Core/Upload/Utils/Argument.cs +++ b/SnapX.Core/Upload/Utils/Argument.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Utils/EscapeHelper.cs b/SnapX.Core/Upload/Utils/EscapeHelper.cs index a2492a08c..ac2c450c6 100644 --- a/SnapX.Core/Upload/Utils/EscapeHelper.cs +++ b/SnapX.Core/Upload/Utils/EscapeHelper.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Utils/ProgressManager.cs b/SnapX.Core/Upload/Utils/ProgressManager.cs index 2a7f9c0d6..d41f8479c 100644 --- a/SnapX.Core/Upload/Utils/ProgressManager.cs +++ b/SnapX.Core/Upload/Utils/ProgressManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Upload/Utils/RequestHelpers.cs b/SnapX.Core/Upload/Utils/RequestHelpers.cs index ed615dd63..6e58caab0 100644 --- a/SnapX.Core/Upload/Utils/RequestHelpers.cs +++ b/SnapX.Core/Upload/Utils/RequestHelpers.cs @@ -1,10 +1,10 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Collections.Specialized; using System.Net; using System.Text; +using MimeTypeCore; using SnapX.Core.Utils.Cryptographic; namespace SnapX.Core.Upload.Utils; @@ -139,14 +139,14 @@ public static byte[] MakeInputContent(string boundary, Dictionary()) + { + if (e.GetLocalizedDescription() == (string)value) + { + return e; + } + } + + return Enum.Parse(enumType, (string)value); + } +} diff --git a/SnapX.Core/Utils/Converters/EnumProperNameConverter.cs b/SnapX.Core/Utils/Converters/EnumProperNameConverter.cs new file mode 100644 index 000000000..513d2219c --- /dev/null +++ b/SnapX.Core/Utils/Converters/EnumProperNameConverter.cs @@ -0,0 +1,38 @@ +using System.ComponentModel; +using System.Globalization; + +namespace SnapX.Core.Utils.Converters; + +public class EnumProperNameConverter(Type Type) : EnumConverter(Type) +{ + private readonly Type enumType = Type; + + public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destType) + { + return destType == typeof(string); + } + + public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destType) + { + ArgumentNullException.ThrowIfNull(value); + return Helpers.GetProperName(value.ToString()!); + } + + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type srcType) + { + return srcType == typeof(string); + } + + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + foreach (Enum e in Enum.GetValues(enumType).OfType()) + { + if (Helpers.GetProperName(e.ToString()) == (string)value) + { + return e; + } + } + + return Enum.Parse(enumType, (string)value); + } +} diff --git a/SnapX.Core/Utils/Converters/EnumProperNameKeepCaseConverter.cs b/SnapX.Core/Utils/Converters/EnumProperNameKeepCaseConverter.cs new file mode 100644 index 000000000..c2e9b737c --- /dev/null +++ b/SnapX.Core/Utils/Converters/EnumProperNameKeepCaseConverter.cs @@ -0,0 +1,39 @@ +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace SnapX.Core.Utils.Converters; + +public class EnumProperNameKeepCaseConverter(Type Type) : EnumConverter(Type) +{ + private Type enumType = Type; + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destType) + { + return destType == typeof(string); + } + + public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destType) + { + return Helpers.GetProperName(value.ToString(), true); + } + + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type srcType) + { + return srcType == typeof(string); + } + + [RequiresUnreferencedCode("Uses Enum.GetValues")] + public override object ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + foreach (Enum e in Enum.GetValues(enumType).OfType()) + { + if (Helpers.GetProperName(e.ToString(), true) == (string)value) + { + return e; + } + } + + return Enum.Parse(enumType, (string)value); + } +} diff --git a/SnapX.Core/Utils/Converters/MyColorConverter.cs b/SnapX.Core/Utils/Converters/MyColorConverter.cs new file mode 100644 index 000000000..01702e878 --- /dev/null +++ b/SnapX.Core/Utils/Converters/MyColorConverter.cs @@ -0,0 +1,42 @@ +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp; + +namespace SnapX.Core.Utils.Converters; + +public class MyColorConverter : TypeConverter +{ + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object ConvertFrom(ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value) + { + if (value is string colorStr) + { + // Try to parse named color first (e.g. "Red") + var knownColor = TryParseKnownColor(colorStr); + if (knownColor is not null) + { + return knownColor.Value; + } + + // Try parse hex value (#RRGGBB or #AARRGGBB) + return colorStr.StartsWith("#") ? Color.ParseHex(colorStr) : throw new FormatException($"Cannot convert '{colorStr}' to ImageSharp Color."); + } + + return base.ConvertFrom(context, culture, value) ?? throw new FormatException($"Cannot convert '{value}' to ImageSharp Color."); + } + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] + [RequiresUnreferencedCode("Checks SixLabors predefined colors")] + private Color? TryParseKnownColor(string name) + { + var colorProperty = typeof(Color).GetProperty(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (colorProperty is not null && colorProperty.PropertyType == typeof(Color)) + { + return (Color)colorProperty.GetValue(null)!; + } + return null; + } +} diff --git a/SnapX.Core/Utils/Converters/StringCollectionToStringTypeConverter.cs b/SnapX.Core/Utils/Converters/StringCollectionToStringTypeConverter.cs new file mode 100644 index 000000000..102f1b7dc --- /dev/null +++ b/SnapX.Core/Utils/Converters/StringCollectionToStringTypeConverter.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; +using System.Globalization; + +namespace SnapX.Core.Utils.UITypeEditors; + +public class StringCollectionToStringTypeConverter : TypeConverter +{ + public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + ArgumentNullException.ThrowIfNull(value); + if (destinationType != typeof(string)) return base.ConvertTo(context, culture, value, destinationType) ?? throw new FormatException($"Cannot convert '{value}' to ImageSharp Color."); + var list = (List)value; + return string.Join(", ", list); + + } +} diff --git a/SnapX.Core/Utils/Cryptographic/HashChecker.cs b/SnapX.Core/Utils/Cryptographic/HashChecker.cs index 2120252ce..2eeb56ca6 100644 --- a/SnapX.Core/Utils/Cryptographic/HashChecker.cs +++ b/SnapX.Core/Utils/Cryptographic/HashChecker.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Cryptographic/Translator.cs b/SnapX.Core/Utils/Cryptographic/Translator.cs index a5a56dab9..31251d0bc 100644 --- a/SnapX.Core/Utils/Cryptographic/Translator.cs +++ b/SnapX.Core/Utils/Cryptographic/Translator.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Cryptographic/TranslatorHelper.cs b/SnapX.Core/Utils/Cryptographic/TranslatorHelper.cs index ee7e3736a..633854a00 100644 --- a/SnapX.Core/Utils/Cryptographic/TranslatorHelper.cs +++ b/SnapX.Core/Utils/Cryptographic/TranslatorHelper.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/DNS/AdapterInfo.cs b/SnapX.Core/Utils/DNS/AdapterInfo.cs index 96b9eff31..54440f6ac 100644 --- a/SnapX.Core/Utils/DNS/AdapterInfo.cs +++ b/SnapX.Core/Utils/DNS/AdapterInfo.cs @@ -1,19 +1,11 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Net.NetworkInformation; namespace SnapX.Core.Utils.DNS; -public class AdapterInfo : IDisposable +public class AdapterInfo(NetworkInterface Adapter) : IDisposable { - private NetworkInterface adapter; - - public AdapterInfo(NetworkInterface adapter) - { - this.adapter = adapter; - } - public static List GetEnabledAdapters() { var adapters = new List(); @@ -28,21 +20,21 @@ public static List GetEnabledAdapters() return adapters; } - public bool IsEnabled() => adapter.OperationalStatus == OperationalStatus.Up; + public bool IsEnabled() => Adapter.OperationalStatus == OperationalStatus.Up; - public string? GetCaption() => adapter.ToString(); + public string? GetCaption() => Adapter.ToString(); - public string GetDescription() => adapter.Description; + public string GetDescription() => Adapter.Description; - public string[] GetDNS() => adapter.GetIPProperties().UnicastAddresses.ToList().Select(x => x.Address.ToString()).ToArray(); + public string[] GetDNS() => Adapter.GetIPProperties().UnicastAddresses.ToList().Select(x => x.Address.ToString()).ToArray(); // TODO: SetDNS needs to be implemented on a per platform basis - public uint SetDNS(string primary, string secondary) => throw new NotImplementedException("SetDNS is not implemented."); + public uint SetDNS(string primary, string? secondary) => throw new NotImplementedException("SetDNS is not implemented."); public uint SetDNSAutomatic() { return SetDNS(null, null); } - public void Dispose() => Console.WriteLine($"Disposed adapter {adapter.Description}"); + public void Dispose() => Console.WriteLine($"Disposed adapter {Adapter.Description}"); public override string ToString() => GetDescription(); } diff --git a/SnapX.Core/Utils/DNS/DNSInfo.cs b/SnapX.Core/Utils/DNS/DNSInfo.cs index 02c12c0b0..18678003d 100644 --- a/SnapX.Core/Utils/DNS/DNSInfo.cs +++ b/SnapX.Core/Utils/DNS/DNSInfo.cs @@ -1,21 +1,13 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.Utils.DNS; -public class DNSInfo +public class DNSInfo(string Name, string PrimaryDns, string SecondaryDns) { - public string Name { get; set; } - public string PrimaryDNS { get; set; } - public string SecondaryDNS { get; set; } - - public DNSInfo(string name, string primaryDNS, string secondaryDNS) - { - Name = name; - PrimaryDNS = primaryDNS; - SecondaryDNS = secondaryDNS; - } + public string Name { get; set; } = Name; + public string PrimaryDNS { get; set; } = PrimaryDns; + public string SecondaryDNS { get; set; } = SecondaryDns; public override string ToString() { diff --git a/SnapX.Core/Utils/Extensions/EnumExtensions.cs b/SnapX.Core/Utils/Extensions/EnumExtensions.cs index a37b52e38..7b4a400ef 100644 --- a/SnapX.Core/Utils/Extensions/EnumExtensions.cs +++ b/SnapX.Core/Utils/Extensions/EnumExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Extensions/Extensions.cs b/SnapX.Core/Utils/Extensions/Extensions.cs index ebefe6a73..dcad94d00 100644 --- a/SnapX.Core/Utils/Extensions/Extensions.cs +++ b/SnapX.Core/Utils/Extensions/Extensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; namespace SnapX.Core.Utils.Extensions; @@ -229,7 +229,10 @@ public static List Range(this List source, T start, T end) return Range(source, startIndex, endIndex); } - public static bool IsTransparent(this Color color) => color.IsTransparent(); + public static bool IsTransparent(this Color color) + { + return color.ToPixel().A < 255; + } public static string ToStringProper(this Rectangle rect) => $"X: {rect.X}, Y: {rect.Y}, Width: {rect.Width}, Height: {rect.Height}"; } diff --git a/SnapX.Core/Utils/Extensions/NumberExtensions.cs b/SnapX.Core/Utils/Extensions/NumberExtensions.cs index 24e0af8d5..93926734b 100644 --- a/SnapX.Core/Utils/Extensions/NumberExtensions.cs +++ b/SnapX.Core/Utils/Extensions/NumberExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Extensions/ObjectExtensions.cs b/SnapX.Core/Utils/Extensions/ObjectExtensions.cs index c7e1aea7e..ac87012fc 100644 --- a/SnapX.Core/Utils/Extensions/ObjectExtensions.cs +++ b/SnapX.Core/Utils/Extensions/ObjectExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Extensions/StreamExtensions.cs b/SnapX.Core/Utils/Extensions/StreamExtensions.cs index deb8e431e..7dfec72c2 100644 --- a/SnapX.Core/Utils/Extensions/StreamExtensions.cs +++ b/SnapX.Core/Utils/Extensions/StreamExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Extensions/StringExtensions.cs b/SnapX.Core/Utils/Extensions/StringExtensions.cs index 4b48df2e7..46e598f0c 100644 --- a/SnapX.Core/Utils/Extensions/StringExtensions.cs +++ b/SnapX.Core/Utils/Extensions/StringExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Extensions/XMLExtensions.cs b/SnapX.Core/Utils/Extensions/XMLExtensions.cs index 7696ce3bc..05ed2a26b 100644 --- a/SnapX.Core/Utils/Extensions/XMLExtensions.cs +++ b/SnapX.Core/Utils/Extensions/XMLExtensions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/FileDownloader.cs b/SnapX.Core/Utils/FileDownloader.cs index 45d6160dd..fcbcde35a 100644 --- a/SnapX.Core/Utils/FileDownloader.cs +++ b/SnapX.Core/Utils/FileDownloader.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/FileHelpers.cs b/SnapX.Core/Utils/FileHelpers.cs index 0724c839a..cdc14fefa 100644 --- a/SnapX.Core/Utils/FileHelpers.cs +++ b/SnapX.Core/Utils/FileHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Helpers.cs b/SnapX.Core/Utils/Helpers.cs index 910b181e3..cfde37c9c 100644 --- a/SnapX.Core/Utils/Helpers.cs +++ b/SnapX.Core/Utils/Helpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/ImageHelpers.cs b/SnapX.Core/Utils/ImageHelpers.cs index 326f3f65a..552367f66 100644 --- a/SnapX.Core/Utils/ImageHelpers.cs +++ b/SnapX.Core/Utils/ImageHelpers.cs @@ -27,29 +27,22 @@ internal static Image ImageDataToImage(uniffi.snapxrust.ImageData imageData) => Image.LoadPixelData(imageData.image, (int)imageData.width, (int)imageData.height); public static Size ApplyAspectRatio(int width, int height, Image img) { - // Get the original aspect ratio of the image - float aspectRatio = (float)img.Width / img.Height; + var aspectRatio = (float)img.Width / img.Height; - // Determine the target aspect ratio (width to height ratio) - float targetAspectRatio = (float)width / height; + var targetAspectRatio = (float)width / height; - // Variables to hold the new width and height - int newWidth = width; - int newHeight = height; + var newWidth = width; + var newHeight = height; - // Adjust the size based on the aspect ratio comparison if (aspectRatio > targetAspectRatio) { - // The image is wider than the target aspect ratio, so adjust based on width - newHeight = (int)(width / aspectRatio); // Calculate new height to maintain aspect ratio + newHeight = (int)(width / aspectRatio); } else if (aspectRatio < targetAspectRatio) { - // The image is taller than the target aspect ratio, so adjust based on height - newWidth = (int)(height * aspectRatio); // Calculate new width to maintain aspect ratio + newWidth = (int)(height * aspectRatio); } - // Return the new size that maintains the aspect ratio return new Size(newWidth, newHeight); } // See how clean the code is?! @@ -57,7 +50,7 @@ public static Size ApplyAspectRatio(int width, int height, Image img) // BLESSED. public static Image ResizeImage(Image img, Size TargetSize, bool preserveAspectRatio = false, bool fill = false, Color? growFillColor = null) { - if (growFillColor == null) growFillColor = Color.Transparent; + growFillColor ??= Color.Transparent; // Mutate the image to apply resizing and fill (if necessary) img.Mutate(ctx => { @@ -431,7 +424,24 @@ public static Image DrawReflection( return finalImage; } - + /// + /// Fills the image with a checkerboard pattern. + /// + public static void DrawCheckerPattern(Image image, int cellSize, Color[] colors) + { + image.Mutate(ctx => + { + for (var y = 0; y < image.Height; y += cellSize) + { + for (var x = 0; x < image.Width; x += cellSize) + { + var isEven = ((x / cellSize) + (y / cellSize)) % 2 == 0; + var color = isEven ? colors[0] : colors[1]; + ctx.Fill(color, new RectangleF(x, y, cellSize, cellSize)); + } + } + }); + } private static float[] CreateAlphaGradient(int height, float maxAlpha, float minAlpha) { float[] gradient = new float[height]; @@ -618,14 +628,10 @@ public static Color GetMostCommonColor(Rgba32[] pixelRow) foreach (var pixel in pixelRow) { var color = new Rgba32(pixel.R, pixel.G, pixel.B); - if (colorCounts.ContainsKey(color)) + if (!colorCounts.TryAdd(color, 1)) { colorCounts[color]++; } - else - { - colorCounts[color] = 1; - } } // Find the color with the maximum count diff --git a/SnapX.Core/Utils/JsonHelpers.cs b/SnapX.Core/Utils/JsonHelpers.cs index fd8db2c05..cd1977925 100644 --- a/SnapX.Core/Utils/JsonHelpers.cs +++ b/SnapX.Core/Utils/JsonHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/MathHelpers.cs b/SnapX.Core/Utils/MathHelpers.cs index f16449545..568b7b834 100644 --- a/SnapX.Core/Utils/MathHelpers.cs +++ b/SnapX.Core/Utils/MathHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/ExternalProgram.cs b/SnapX.Core/Utils/Miscellaneous/ExternalProgram.cs index a81b4da67..22335c7da 100644 --- a/SnapX.Core/Utils/Miscellaneous/ExternalProgram.cs +++ b/SnapX.Core/Utils/Miscellaneous/ExternalProgram.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/FPSManager.cs b/SnapX.Core/Utils/Miscellaneous/FPSManager.cs index ca918300d..101be9d61 100644 --- a/SnapX.Core/Utils/Miscellaneous/FPSManager.cs +++ b/SnapX.Core/Utils/Miscellaneous/FPSManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,30 +5,19 @@ namespace SnapX.Core.Utils.Miscellaneous; -public class FPSManager +public class FPSManager(int FPSLimit) { public event Action FPSUpdated; public int FPS { get; private set; } - public int FPSLimit { get; set; } private int frameCount; - private Stopwatch fpsTimer, frameTimer; - - public FPSManager() - { - fpsTimer = new Stopwatch(); - frameTimer = new Stopwatch(); - } + private readonly Stopwatch fpsTimer = new(); + private readonly Stopwatch frameTimer = new(); - public FPSManager(int fpsLimit) : this() + private void OnFPSUpdated() { - FPSLimit = fpsLimit; - } - - protected void OnFPSUpdated() - { - FPSUpdated?.Invoke(); + FPSUpdated.Invoke(); } public void Update() @@ -39,7 +27,7 @@ public void Update() if (!fpsTimer.IsRunning) fpsTimer.Start(); else if (fpsTimer.ElapsedMilliseconds >= 1000) { - FPS = (int)System.Math.Round(frameCount / fpsTimer.Elapsed.TotalSeconds); + FPS = (int)Math.Round(frameCount / fpsTimer.Elapsed.TotalSeconds); OnFPSUpdated(); @@ -47,29 +35,27 @@ public void Update() fpsTimer.Restart(); } - if (FPSLimit > 0) + if (FPSLimit <= 0) return; + if (!frameTimer.IsRunning) { - if (!frameTimer.IsRunning) - { - frameTimer.Start(); - } - else + frameTimer.Start(); + } + else + { + var currentFrameDuration = frameTimer.Elapsed.TotalMilliseconds; + var targetFrameDuration = 1000d / FPSLimit; + + if (currentFrameDuration < targetFrameDuration) { - double currentFrameDuration = frameTimer.Elapsed.TotalMilliseconds; - double targetFrameDuration = 1000d / FPSLimit; + var sleepDuration = (int)Math.Round(targetFrameDuration - currentFrameDuration); - if (currentFrameDuration < targetFrameDuration) + if (sleepDuration > 0) { - int sleepDuration = (int)System.Math.Round(targetFrameDuration - currentFrameDuration); - - if (sleepDuration > 0) - { - Thread.Sleep(sleepDuration); - } + Thread.Sleep(sleepDuration); } - - frameTimer.Restart(); } + + frameTimer.Restart(); } } } diff --git a/SnapX.Core/Utils/Miscellaneous/FastDateTime.cs b/SnapX.Core/Utils/Miscellaneous/FastDateTime.cs deleted file mode 100644 index 00af5b7a5..000000000 --- a/SnapX.Core/Utils/Miscellaneous/FastDateTime.cs +++ /dev/null @@ -1,38 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - - -namespace SnapX.Core.Utils.Miscellaneous; - -public static class FastDateTime -{ - public static TimeSpan LocalUtcOffset { get; private set; } - - public static DateTime Now - { - get - { - return ToLocalTime(DateTime.UtcNow); - } - } - - public static long NowUnix - { - get - { - return (DateTime.UtcNow.Ticks - 621355968000000000) / 10000000; - } - } - - static FastDateTime() - { - LocalUtcOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now); - } - - public static DateTime ToLocalTime(DateTime dateTime) - { - return dateTime + LocalUtcOffset; - } -} - diff --git a/SnapX.Core/Utils/Miscellaneous/FixedSizedQueue.cs b/SnapX.Core/Utils/Miscellaneous/FixedSizedQueue.cs index da68b7343..6a9b4565a 100644 --- a/SnapX.Core/Utils/Miscellaneous/FixedSizedQueue.cs +++ b/SnapX.Core/Utils/Miscellaneous/FixedSizedQueue.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/HelpersOptions.cs b/SnapX.Core/Utils/Miscellaneous/HelpersOptions.cs index 3aad0be08..378abe078 100644 --- a/SnapX.Core/Utils/Miscellaneous/HelpersOptions.cs +++ b/SnapX.Core/Utils/Miscellaneous/HelpersOptions.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/HttpClientFactory.cs b/SnapX.Core/Utils/Miscellaneous/HttpClientFactory.cs index 188fece7e..3336fb985 100644 --- a/SnapX.Core/Utils/Miscellaneous/HttpClientFactory.cs +++ b/SnapX.Core/Utils/Miscellaneous/HttpClientFactory.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/Links.cs b/SnapX.Core/Utils/Miscellaneous/Links.cs index e14a30a9e..ad6e2dbb9 100644 --- a/SnapX.Core/Utils/Miscellaneous/Links.cs +++ b/SnapX.Core/Utils/Miscellaneous/Links.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/MaxLengthStream.cs b/SnapX.Core/Utils/Miscellaneous/MaxLengthStream.cs index 57c6a832a..169a631f8 100644 --- a/SnapX.Core/Utils/Miscellaneous/MaxLengthStream.cs +++ b/SnapX.Core/Utils/Miscellaneous/MaxLengthStream.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/MimeTypesPlus.cs b/SnapX.Core/Utils/Miscellaneous/MimeTypesPlus.cs deleted file mode 100644 index b3ec28e08..000000000 --- a/SnapX.Core/Utils/Miscellaneous/MimeTypesPlus.cs +++ /dev/null @@ -1,1008 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -namespace SnapX.Core.Utils.Miscellaneous; - -public static class MimeTypesPlus -{ - public static bool IsImageMimeType(string mimeType) - { - return !string.IsNullOrEmpty(mimeType) && - (mimeType.Equals(Mappings["png"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["apng"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["jpeg"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["gif"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["bmp"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["webp"], StringComparison.OrdinalIgnoreCase) || - mimeType.Equals(Mappings["tiff"], StringComparison.OrdinalIgnoreCase)); - } - - // http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types - private static Dictionary Mappings = new(StringComparer.OrdinalIgnoreCase) - { - { "123", "application/vnd.lotus-1-2-3" }, - { "3dml", "text/vnd.in3d.3dml" }, - { "3ds", "image/x-3ds" }, - { "3g2", "video/3gpp2" }, - { "3gp", "video/3gpp" }, - { "7z", "application/x-7z-compressed" }, - { "aab", "application/x-authorware-bin" }, - { "aac", "audio/x-aac" }, - { "aam", "application/x-authorware-map" }, - { "aas", "application/x-authorware-seg" }, - { "abw", "application/x-abiword" }, - { "ac", "application/pkix-attr-cert" }, - { "acc", "application/vnd.americandynamics.acc" }, - { "ace", "application/x-ace-compressed" }, - { "acu", "application/vnd.acucobol" }, - { "acutc", "application/vnd.acucorp" }, - { "adp", "audio/adpcm" }, - { "aep", "application/vnd.audiograph" }, - { "afm", "application/x-font-type1" }, - { "afp", "application/vnd.ibm.modcap" }, - { "ahead", "application/vnd.ahead.space" }, - { "ai", "application/postscript" }, - { "aif", "audio/x-aiff" }, - { "aifc", "audio/x-aiff" }, - { "aiff", "audio/x-aiff" }, - { "air", "application/vnd.adobe.air-application-installer-package+zip" }, - { "ait", "application/vnd.dvb.ait" }, - { "ami", "application/vnd.amiga.ami" }, - { "apk", "application/vnd.android.package-archive" }, - { "apng", "image/apng" }, - { "appcache", "text/cache-manifest" }, - { "application", "application/x-ms-application" }, - { "apr", "application/vnd.lotus-approach" }, - { "arc", "application/x-freearc" }, - { "asc", "application/pgp-signature" }, - { "asf", "video/x-ms-asf" }, - { "asm", "text/x-asm" }, - { "aso", "application/vnd.accpac.simply.aso" }, - { "asx", "video/x-ms-asf" }, - { "atc", "application/vnd.acucorp" }, - { "atom", "application/atom+xml" }, - { "atomcat", "application/atomcat+xml" }, - { "atomsvc", "application/atomsvc+xml" }, - { "atx", "application/vnd.antix.game-component" }, - { "au", "audio/basic" }, - { "avi", "video/x-msvideo" }, - { "aw", "application/applixware" }, - { "azf", "application/vnd.airzip.filesecure.azf" }, - { "azs", "application/vnd.airzip.filesecure.azs" }, - { "azw", "application/vnd.amazon.ebook" }, - { "bat", "application/x-msdownload" }, - { "bcpio", "application/x-bcpio" }, - { "bdf", "application/x-font-bdf" }, - { "bdm", "application/vnd.syncml.dm+wbxml" }, - { "bed", "application/vnd.realvnc.bed" }, - { "bh2", "application/vnd.fujitsu.oasysprs" }, - { "bin", "application/octet-stream" }, - { "blb", "application/x-blorb" }, - { "blorb", "application/x-blorb" }, - { "bmi", "application/vnd.bmi" }, - { "bmp", "image/bmp" }, - { "book", "application/vnd.framemaker" }, - { "box", "application/vnd.previewsystems.box" }, - { "boz", "application/x-bzip2" }, - { "bpk", "application/octet-stream" }, - { "btif", "image/prs.btif" }, - { "bz", "application/x-bzip" }, - { "bz2", "application/x-bzip2" }, - { "c", "text/x-c" }, - { "c11amc", "application/vnd.cluetrust.cartomobile-config" }, - { "c11amz", "application/vnd.cluetrust.cartomobile-config-pkg" }, - { "c4d", "application/vnd.clonk.c4group" }, - { "c4f", "application/vnd.clonk.c4group" }, - { "c4g", "application/vnd.clonk.c4group" }, - { "c4p", "application/vnd.clonk.c4group" }, - { "c4u", "application/vnd.clonk.c4group" }, - { "cab", "application/vnd.ms-cab-compressed" }, - { "caf", "audio/x-caf" }, - { "cap", "application/vnd.tcpdump.pcap" }, - { "car", "application/vnd.curl.car" }, - { "cat", "application/vnd.ms-pki.seccat" }, - { "cb7", "application/x-cbr" }, - { "cba", "application/x-cbr" }, - { "cbr", "application/x-cbr" }, - { "cbt", "application/x-cbr" }, - { "cbz", "application/x-cbr" }, - { "cc", "text/x-c" }, - { "cct", "application/x-director" }, - { "ccxml", "application/ccxml+xml" }, - { "cdbcmsg", "application/vnd.contact.cmsg" }, - { "cdf", "application/x-netcdf" }, - { "cdkey", "application/vnd.mediastation.cdkey" }, - { "cdmia", "application/cdmi-capability" }, - { "cdmic", "application/cdmi-container" }, - { "cdmid", "application/cdmi-domain" }, - { "cdmio", "application/cdmi-object" }, - { "cdmiq", "application/cdmi-queue" }, - { "cdx", "chemical/x-cdx" }, - { "cdxml", "application/vnd.chemdraw+xml" }, - { "cdy", "application/vnd.cinderella" }, - { "cer", "application/pkix-cert" }, - { "cfs", "application/x-cfs-compressed" }, - { "cgm", "image/cgm" }, - { "chat", "application/x-chat" }, - { "chm", "application/vnd.ms-htmlhelp" }, - { "chrt", "application/vnd.kde.kchart" }, - { "cif", "chemical/x-cif" }, - { "cii", "application/vnd.anser-web-certificate-issue-initiation" }, - { "cil", "application/vnd.ms-artgalry" }, - { "cla", "application/vnd.claymore" }, - { "class", "application/java-vm" }, - { "clkk", "application/vnd.crick.clicker.keyboard" }, - { "clkp", "application/vnd.crick.clicker.palette" }, - { "clkt", "application/vnd.crick.clicker.template" }, - { "clkw", "application/vnd.crick.clicker.wordbank" }, - { "clkx", "application/vnd.crick.clicker" }, - { "clp", "application/x-msclip" }, - { "cmc", "application/vnd.cosmocaller" }, - { "cmdf", "chemical/x-cmdf" }, - { "cml", "chemical/x-cml" }, - { "cmp", "application/vnd.yellowriver-custom-menu" }, - { "cmx", "image/x-cmx" }, - { "cod", "application/vnd.rim.cod" }, - { "com", "application/x-msdownload" }, - { "conf", "text/plain" }, - { "cpio", "application/x-cpio" }, - { "cpp", "text/x-c" }, - { "cpt", "application/mac-compactpro" }, - { "crd", "application/x-mscardfile" }, - { "crl", "application/pkix-crl" }, - { "crt", "application/x-x509-ca-cert" }, - { "cryptonote", "application/vnd.rig.cryptonote" }, - { "csh", "application/x-csh" }, - { "csml", "chemical/x-csml" }, - { "csp", "application/vnd.commonspace" }, - { "css", "text/css" }, - { "cst", "application/x-director" }, - { "csv", "text/csv" }, - { "cu", "application/cu-seeme" }, - { "curl", "text/vnd.curl" }, - { "cww", "application/prs.cww" }, - { "cxt", "application/x-director" }, - { "cxx", "text/x-c" }, - { "dae", "model/vnd.collada+xml" }, - { "daf", "application/vnd.mobius.daf" }, - { "dart", "application/vnd.dart" }, - { "dataless", "application/vnd.fdsn.seed" }, - { "davmount", "application/davmount+xml" }, - { "dbk", "application/docbook+xml" }, - { "dcr", "application/x-director" }, - { "dcurl", "text/vnd.curl.dcurl" }, - { "dd2", "application/vnd.oma.dd2+xml" }, - { "ddd", "application/vnd.fujixerox.ddd" }, - { "deb", "application/x-debian-package" }, - { "def", "text/plain" }, - { "deploy", "application/octet-stream" }, - { "der", "application/x-x509-ca-cert" }, - { "dfac", "application/vnd.dreamfactory" }, - { "dgc", "application/x-dgc-compressed" }, - { "dic", "text/x-c" }, - { "dir", "application/x-director" }, - { "dis", "application/vnd.mobius.dis" }, - { "dist", "application/octet-stream" }, - { "distz", "application/octet-stream" }, - { "djv", "image/vnd.djvu" }, - { "djvu", "image/vnd.djvu" }, - { "dll", "application/x-msdownload" }, - { "dmg", "application/x-apple-diskimage" }, - { "dmp", "application/vnd.tcpdump.pcap" }, - { "dms", "application/octet-stream" }, - { "dna", "application/vnd.dna" }, - { "doc", "application/msword" }, - { "docm", "application/vnd.ms-word.document.macroenabled.12" }, - { "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, - { "dot", "application/msword" }, - { "dotm", "application/vnd.ms-word.template.macroenabled.12" }, - { "dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" }, - { "dp", "application/vnd.osgi.dp" }, - { "dpg", "application/vnd.dpgraph" }, - { "dra", "audio/vnd.dra" }, - { "dsc", "text/prs.lines.tag" }, - { "dssc", "application/dssc+der" }, - { "dtb", "application/x-dtbook+xml" }, - { "dtd", "application/xml-dtd" }, - { "dts", "audio/vnd.dts" }, - { "dtshd", "audio/vnd.dts.hd" }, - { "dump", "application/octet-stream" }, - { "dvb", "video/vnd.dvb.file" }, - { "dvi", "application/x-dvi" }, - { "dwf", "model/vnd.dwf" }, - { "dwg", "image/vnd.dwg" }, - { "dxf", "image/vnd.dxf" }, - { "dxp", "application/vnd.spotfire.dxp" }, - { "dxr", "application/x-director" }, - { "ecelp4800", "audio/vnd.nuera.ecelp4800" }, - { "ecelp7470", "audio/vnd.nuera.ecelp7470" }, - { "ecelp9600", "audio/vnd.nuera.ecelp9600" }, - { "ecma", "application/ecmascript" }, - { "edm", "application/vnd.novadigm.edm" }, - { "edx", "application/vnd.novadigm.edx" }, - { "efif", "application/vnd.picsel" }, - { "ei6", "application/vnd.pg.osasli" }, - { "elc", "application/octet-stream" }, - { "emf", "application/x-msmetafile" }, - { "eml", "message/rfc822" }, - { "emma", "application/emma+xml" }, - { "emz", "application/x-msmetafile" }, - { "eol", "audio/vnd.digital-winds" }, - { "eot", "application/vnd.ms-fontobject" }, - { "eps", "application/postscript" }, - { "epub", "application/epub+zip" }, - { "es3", "application/vnd.eszigno3+xml" }, - { "esa", "application/vnd.osgi.subsystem" }, - { "esf", "application/vnd.epson.esf" }, - { "et3", "application/vnd.eszigno3+xml" }, - { "etx", "text/x-setext" }, - { "eva", "application/x-eva" }, - { "evy", "application/x-envoy" }, - { "exe", "application/x-msdownload" }, - { "exi", "application/exi" }, - { "ext", "application/vnd.novadigm.ext" }, - { "ez", "application/andrew-inset" }, - { "ez2", "application/vnd.ezpix-album" }, - { "ez3", "application/vnd.ezpix-package" }, - { "f", "text/x-fortran" }, - { "f4v", "video/x-f4v" }, - { "f77", "text/x-fortran" }, - { "f90", "text/x-fortran" }, - { "fbs", "image/vnd.fastbidsheet" }, - { "fcdt", "application/vnd.adobe.formscentral.fcdt" }, - { "fcs", "application/vnd.isac.fcs" }, - { "fdf", "application/vnd.fdf" }, - { "fe_launch", "application/vnd.denovo.fcselayout-link" }, - { "fg5", "application/vnd.fujitsu.oasysgp" }, - { "fgd", "application/x-director" }, - { "fh", "image/x-freehand" }, - { "fh4", "image/x-freehand" }, - { "fh5", "image/x-freehand" }, - { "fh7", "image/x-freehand" }, - { "fhc", "image/x-freehand" }, - { "fig", "application/x-xfig" }, - { "flac", "audio/x-flac" }, - { "fli", "video/x-fli" }, - { "flo", "application/vnd.micrografx.flo" }, - { "flv", "video/x-flv" }, - { "flw", "application/vnd.kde.kivio" }, - { "flx", "text/vnd.fmi.flexstor" }, - { "fly", "text/vnd.fly" }, - { "fm", "application/vnd.framemaker" }, - { "fnc", "application/vnd.frogans.fnc" }, - { "for", "text/x-fortran" }, - { "fpx", "image/vnd.fpx" }, - { "frame", "application/vnd.framemaker" }, - { "fsc", "application/vnd.fsc.weblaunch" }, - { "fst", "image/vnd.fst" }, - { "ftc", "application/vnd.fluxtime.clip" }, - { "fti", "application/vnd.anser-web-funds-transfer-initiation" }, - { "fvt", "video/vnd.fvt" }, - { "fxp", "application/vnd.adobe.fxp" }, - { "fxpl", "application/vnd.adobe.fxp" }, - { "fzs", "application/vnd.fuzzysheet" }, - { "g2w", "application/vnd.geoplan" }, - { "g3", "image/g3fax" }, - { "g3w", "application/vnd.geospace" }, - { "gac", "application/vnd.groove-account" }, - { "gam", "application/x-tads" }, - { "gbr", "application/rpki-ghostbusters" }, - { "gca", "application/x-gca-compressed" }, - { "gdl", "model/vnd.gdl" }, - { "geo", "application/vnd.dynageo" }, - { "gex", "application/vnd.geometry-explorer" }, - { "ggb", "application/vnd.geogebra.file" }, - { "ggt", "application/vnd.geogebra.tool" }, - { "ghf", "application/vnd.groove-help" }, - { "gif", "image/gif" }, - { "gim", "application/vnd.groove-identity-message" }, - { "gml", "application/gml+xml" }, - { "gmx", "application/vnd.gmx" }, - { "gnumeric", "application/x-gnumeric" }, - { "gph", "application/vnd.flographit" }, - { "gpx", "application/gpx+xml" }, - { "gqf", "application/vnd.grafeq" }, - { "gqs", "application/vnd.grafeq" }, - { "gram", "application/srgs" }, - { "gramps", "application/x-gramps-xml" }, - { "gre", "application/vnd.geometry-explorer" }, - { "grv", "application/vnd.groove-injector" }, - { "grxml", "application/srgs+xml" }, - { "gsf", "application/x-font-ghostscript" }, - { "gtar", "application/x-gtar" }, - { "gtm", "application/vnd.groove-tool-message" }, - { "gtw", "model/vnd.gtw" }, - { "gv", "text/vnd.graphviz" }, - { "gxf", "application/gxf" }, - { "gxt", "application/vnd.geonext" }, - { "h", "text/x-c" }, - { "h261", "video/h261" }, - { "h263", "video/h263" }, - { "h264", "video/h264" }, - { "hal", "application/vnd.hal+xml" }, - { "hbci", "application/vnd.hbci" }, - { "hdf", "application/x-hdf" }, - { "hh", "text/x-c" }, - { "hlp", "application/winhlp" }, - { "hpgl", "application/vnd.hp-hpgl" }, - { "hpid", "application/vnd.hp-hpid" }, - { "hps", "application/vnd.hp-hps" }, - { "hqx", "application/mac-binhex40" }, - { "htke", "application/vnd.kenameaapp" }, - { "htm", "text/html" }, - { "html", "text/html" }, - { "hvd", "application/vnd.yamaha.hv-dic" }, - { "hvp", "application/vnd.yamaha.hv-voice" }, - { "hvs", "application/vnd.yamaha.hv-script" }, - { "i2g", "application/vnd.intergeo" }, - { "icc", "application/vnd.iccprofile" }, - { "ice", "x-conference/x-cooltalk" }, - { "icm", "application/vnd.iccprofile" }, - { "ico", "image/x-icon" }, - { "ics", "text/calendar" }, - { "ief", "image/ief" }, - { "ifb", "text/calendar" }, - { "ifm", "application/vnd.shana.informed.formdata" }, - { "iges", "model/iges" }, - { "igl", "application/vnd.igloader" }, - { "igm", "application/vnd.insors.igm" }, - { "igs", "model/iges" }, - { "igx", "application/vnd.micrografx.igx" }, - { "iif", "application/vnd.shana.informed.interchange" }, - { "imp", "application/vnd.accpac.simply.imp" }, - { "ims", "application/vnd.ms-ims" }, - { "in", "text/plain" }, - { "ink", "application/inkml+xml" }, - { "inkml", "application/inkml+xml" }, - { "install", "application/x-install-instructions" }, - { "iota", "application/vnd.astraea-software.iota" }, - { "ipfix", "application/ipfix" }, - { "ipk", "application/vnd.shana.informed.package" }, - { "irm", "application/vnd.ibm.rights-management" }, - { "irp", "application/vnd.irepository.package+xml" }, - { "iso", "application/x-iso9660-image" }, - { "itp", "application/vnd.shana.informed.formtemplate" }, - { "ivp", "application/vnd.immervision-ivp" }, - { "ivu", "application/vnd.immervision-ivu" }, - { "jad", "text/vnd.sun.j2me.app-descriptor" }, - { "jam", "application/vnd.jam" }, - { "jar", "application/java-archive" }, - { "java", "text/x-java-source" }, - { "jisp", "application/vnd.jisp" }, - { "jlt", "application/vnd.hp-jlyt" }, - { "jnlp", "application/x-java-jnlp-file" }, - { "joda", "application/vnd.joost.joda-archive" }, - { "jpe", "image/jpeg" }, - { "jpeg", "image/jpeg" }, - { "jpg", "image/jpeg" }, - { "jpgm", "video/jpm" }, - { "jpgv", "video/jpeg" }, - { "jpm", "video/jpm" }, - { "js", "application/javascript" }, - { "json", "application/json" }, - { "jsonml", "application/jsonml+json" }, - { "kar", "audio/midi" }, - { "karbon", "application/vnd.kde.karbon" }, - { "kfo", "application/vnd.kde.kformula" }, - { "kia", "application/vnd.kidspiration" }, - { "kml", "application/vnd.google-earth.kml+xml" }, - { "kmz", "application/vnd.google-earth.kmz" }, - { "kne", "application/vnd.kinar" }, - { "knp", "application/vnd.kinar" }, - { "kon", "application/vnd.kde.kontour" }, - { "kpr", "application/vnd.kde.kpresenter" }, - { "kpt", "application/vnd.kde.kpresenter" }, - { "kpxx", "application/vnd.ds-keypoint" }, - { "ksp", "application/vnd.kde.kspread" }, - { "ktr", "application/vnd.kahootz" }, - { "ktx", "image/ktx" }, - { "ktz", "application/vnd.kahootz" }, - { "kwd", "application/vnd.kde.kword" }, - { "kwt", "application/vnd.kde.kword" }, - { "lasxml", "application/vnd.las.las+xml" }, - { "latex", "application/x-latex" }, - { "lbd", "application/vnd.llamagraphics.life-balance.desktop" }, - { "lbe", "application/vnd.llamagraphics.life-balance.exchange+xml" }, - { "les", "application/vnd.hhe.lesson-player" }, - { "lha", "application/x-lzh-compressed" }, - { "link66", "application/vnd.route66.link66+xml" }, - { "list", "text/plain" }, - { "list3820", "application/vnd.ibm.modcap" }, - { "listafp", "application/vnd.ibm.modcap" }, - { "lnk", "application/x-ms-shortcut" }, - { "log", "text/plain" }, - { "lostxml", "application/lost+xml" }, - { "lrf", "application/octet-stream" }, - { "lrm", "application/vnd.ms-lrm" }, - { "ltf", "application/vnd.frogans.ltf" }, - { "lvp", "audio/vnd.lucent.voice" }, - { "lwp", "application/vnd.lotus-wordpro" }, - { "lzh", "application/x-lzh-compressed" }, - { "m13", "application/x-msmediaview" }, - { "m14", "application/x-msmediaview" }, - { "m1v", "video/mpeg" }, - { "m21", "application/mp21" }, - { "m2a", "audio/mpeg" }, - { "m2v", "video/mpeg" }, - { "m3a", "audio/mpeg" }, - { "m3u", "audio/x-mpegurl" }, - { "m3u8", "application/vnd.apple.mpegurl" }, - { "m4u", "video/vnd.mpegurl" }, - { "m4v", "video/x-m4v" }, - { "ma", "application/mathematica" }, - { "mads", "application/mads+xml" }, - { "mag", "application/vnd.ecowin.chart" }, - { "maker", "application/vnd.framemaker" }, - { "man", "text/troff" }, - { "mar", "application/octet-stream" }, - { "mathml", "application/mathml+xml" }, - { "mb", "application/mathematica" }, - { "mbk", "application/vnd.mobius.mbk" }, - { "mbox", "application/mbox" }, - { "mc1", "application/vnd.medcalcdata" }, - { "mcd", "application/vnd.mcd" }, - { "mcurl", "text/vnd.curl.mcurl" }, - { "mdb", "application/x-msaccess" }, - { "mdi", "image/vnd.ms-modi" }, - { "me", "text/troff" }, - { "mesh", "model/mesh" }, - { "meta4", "application/metalink4+xml" }, - { "metalink", "application/metalink+xml" }, - { "mets", "application/mets+xml" }, - { "mfm", "application/vnd.mfmp" }, - { "mft", "application/rpki-manifest" }, - { "mgp", "application/vnd.osgeo.mapguide.package" }, - { "mgz", "application/vnd.proteus.magazine" }, - { "mid", "audio/midi" }, - { "midi", "audio/midi" }, - { "mie", "application/x-mie" }, - { "mif", "application/vnd.mif" }, - { "mime", "message/rfc822" }, - { "mj2", "video/mj2" }, - { "mjp2", "video/mj2" }, - { "mk3d", "video/x-matroska" }, - { "mka", "audio/x-matroska" }, - { "mks", "video/x-matroska" }, - { "mkv", "video/x-matroska" }, - { "mlp", "application/vnd.dolby.mlp" }, - { "mmd", "application/vnd.chipnuts.karaoke-mmd" }, - { "mmf", "application/vnd.smaf" }, - { "mmr", "image/vnd.fujixerox.edmics-mmr" }, - { "mng", "video/x-mng" }, - { "mny", "application/x-msmoney" }, - { "mobi", "application/x-mobipocket-ebook" }, - { "mods", "application/mods+xml" }, - { "mov", "video/quicktime" }, - { "movie", "video/x-sgi-movie" }, - { "mp2", "audio/mpeg" }, - { "mp21", "application/mp21" }, - { "mp2a", "audio/mpeg" }, - { "mp3", "audio/mpeg" }, - { "mp4", "video/mp4" }, - { "mp4a", "audio/mp4" }, - { "mp4s", "application/mp4" }, - { "mp4v", "video/mp4" }, - { "mpc", "application/vnd.mophun.certificate" }, - { "mpe", "video/mpeg" }, - { "mpeg", "video/mpeg" }, - { "mpg", "video/mpeg" }, - { "mpg4", "video/mp4" }, - { "mpga", "audio/mpeg" }, - { "mpkg", "application/vnd.apple.installer+xml" }, - { "mpm", "application/vnd.blueice.multipass" }, - { "mpn", "application/vnd.mophun.application" }, - { "mpp", "application/vnd.ms-project" }, - { "mpt", "application/vnd.ms-project" }, - { "mpy", "application/vnd.ibm.minipay" }, - { "mqy", "application/vnd.mobius.mqy" }, - { "mrc", "application/marc" }, - { "mrcx", "application/marcxml+xml" }, - { "ms", "text/troff" }, - { "mscml", "application/mediaservercontrol+xml" }, - { "mseed", "application/vnd.fdsn.mseed" }, - { "mseq", "application/vnd.mseq" }, - { "msf", "application/vnd.epson.msf" }, - { "msh", "model/mesh" }, - { "msi", "application/x-msdownload" }, - { "msl", "application/vnd.mobius.msl" }, - { "msty", "application/vnd.muvee.style" }, - { "mts", "model/vnd.mts" }, - { "mus", "application/vnd.musician" }, - { "musicxml", "application/vnd.recordare.musicxml+xml" }, - { "mvb", "application/x-msmediaview" }, - { "mwf", "application/vnd.mfer" }, - { "mxf", "application/mxf" }, - { "mxl", "application/vnd.recordare.musicxml" }, - { "mxml", "application/xv+xml" }, - { "mxs", "application/vnd.triscape.mxs" }, - { "mxu", "video/vnd.mpegurl" }, - { "n3", "text/n3" }, - { "nb", "application/mathematica" }, - { "nbp", "application/vnd.wolfram.player" }, - { "nc", "application/x-netcdf" }, - { "ncx", "application/x-dtbncx+xml" }, - { "nfo", "text/x-nfo" }, - { "n-gage", "application/vnd.nokia.n-gage.symbian.install" }, - { "ngdat", "application/vnd.nokia.n-gage.data" }, - { "nitf", "application/vnd.nitf" }, - { "nlu", "application/vnd.neurolanguage.nlu" }, - { "nml", "application/vnd.enliven" }, - { "nnd", "application/vnd.noblenet-directory" }, - { "nns", "application/vnd.noblenet-sealer" }, - { "nnw", "application/vnd.noblenet-web" }, - { "npx", "image/vnd.net-fpx" }, - { "nsc", "application/x-conference" }, - { "nsf", "application/vnd.lotus-notes" }, - { "ntf", "application/vnd.nitf" }, - { "nzb", "application/x-nzb" }, - { "oa2", "application/vnd.fujitsu.oasys2" }, - { "oa3", "application/vnd.fujitsu.oasys3" }, - { "oas", "application/vnd.fujitsu.oasys" }, - { "obd", "application/x-msbinder" }, - { "obj", "application/x-tgif" }, - { "oda", "application/oda" }, - { "odb", "application/vnd.oasis.opendocument.database" }, - { "odc", "application/vnd.oasis.opendocument.chart" }, - { "odf", "application/vnd.oasis.opendocument.formula" }, - { "odft", "application/vnd.oasis.opendocument.formula-template" }, - { "odg", "application/vnd.oasis.opendocument.graphics" }, - { "odi", "application/vnd.oasis.opendocument.image" }, - { "odm", "application/vnd.oasis.opendocument.text-master" }, - { "odp", "application/vnd.oasis.opendocument.presentation" }, - { "ods", "application/vnd.oasis.opendocument.spreadsheet" }, - { "odt", "application/vnd.oasis.opendocument.text" }, - { "oga", "audio/ogg" }, - { "ogg", "audio/ogg" }, - { "ogv", "video/ogg" }, - { "ogx", "application/ogg" }, - { "omdoc", "application/omdoc+xml" }, - { "onepkg", "application/onenote" }, - { "onetmp", "application/onenote" }, - { "onetoc", "application/onenote" }, - { "onetoc2", "application/onenote" }, - { "opf", "application/oebps-package+xml" }, - { "opml", "text/x-opml" }, - { "oprc", "application/vnd.palm" }, - { "org", "application/vnd.lotus-organizer" }, - { "osf", "application/vnd.yamaha.openscoreformat" }, - { "osfpvg", "application/vnd.yamaha.openscoreformat.osfpvg+xml" }, - { "otc", "application/vnd.oasis.opendocument.chart-template" }, - { "otf", "application/x-font-otf" }, - { "otg", "application/vnd.oasis.opendocument.graphics-template" }, - { "oth", "application/vnd.oasis.opendocument.text-web" }, - { "oti", "application/vnd.oasis.opendocument.image-template" }, - { "otp", "application/vnd.oasis.opendocument.presentation-template" }, - { "ots", "application/vnd.oasis.opendocument.spreadsheet-template" }, - { "ott", "application/vnd.oasis.opendocument.text-template" }, - { "oxps", "application/oxps" }, - { "oxt", "application/vnd.openofficeorg.extension" }, - { "p", "text/x-pascal" }, - { "p10", "application/pkcs10" }, - { "p12", "application/x-pkcs12" }, - { "p7b", "application/x-pkcs7-certificates" }, - { "p7c", "application/pkcs7-mime" }, - { "p7m", "application/pkcs7-mime" }, - { "p7r", "application/x-pkcs7-certreqresp" }, - { "p7s", "application/pkcs7-signature" }, - { "p8", "application/pkcs8" }, - { "pas", "text/x-pascal" }, - { "paw", "application/vnd.pawaafile" }, - { "pbd", "application/vnd.powerbuilder6" }, - { "pbm", "image/x-portable-bitmap" }, - { "pcap", "application/vnd.tcpdump.pcap" }, - { "pcf", "application/x-font-pcf" }, - { "pcl", "application/vnd.hp-pcl" }, - { "pclxl", "application/vnd.hp-pclxl" }, - { "pct", "image/x-pict" }, - { "pcurl", "application/vnd.curl.pcurl" }, - { "pcx", "image/x-pcx" }, - { "pdb", "application/vnd.palm" }, - { "pdf", "application/pdf" }, - { "pfa", "application/x-font-type1" }, - { "pfb", "application/x-font-type1" }, - { "pfm", "application/x-font-type1" }, - { "pfr", "application/font-tdpfr" }, - { "pfx", "application/x-pkcs12" }, - { "pgm", "image/x-portable-graymap" }, - { "pgn", "application/x-chess-pgn" }, - { "pgp", "application/pgp-encrypted" }, - { "pic", "image/x-pict" }, - { "pkg", "application/octet-stream" }, - { "pki", "application/pkixcmp" }, - { "pkipath", "application/pkix-pkipath" }, - { "plb", "application/vnd.3gpp.pic-bw-large" }, - { "plc", "application/vnd.mobius.plc" }, - { "plf", "application/vnd.pocketlearn" }, - { "pls", "application/pls+xml" }, - { "pml", "application/vnd.ctc-posml" }, - { "png", "image/png" }, - { "pnm", "image/x-portable-anymap" }, - { "portpkg", "application/vnd.macports.portpkg" }, - { "pot", "application/vnd.ms-powerpoint" }, - { "potm", "application/vnd.ms-powerpoint.template.macroenabled.12" }, - { "potx", "application/vnd.openxmlformats-officedocument.presentationml.template" }, - { "ppam", "application/vnd.ms-powerpoint.addin.macroenabled.12" }, - { "ppd", "application/vnd.cups-ppd" }, - { "ppm", "image/x-portable-pixmap" }, - { "pps", "application/vnd.ms-powerpoint" }, - { "ppsm", "application/vnd.ms-powerpoint.slideshow.macroenabled.12" }, - { "ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" }, - { "ppt", "application/vnd.ms-powerpoint" }, - { "pptm", "application/vnd.ms-powerpoint.presentation.macroenabled.12" }, - { "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, - { "pqa", "application/vnd.palm" }, - { "prc", "application/x-mobipocket-ebook" }, - { "pre", "application/vnd.lotus-freelance" }, - { "prf", "application/pics-rules" }, - { "ps", "application/postscript" }, - { "psb", "application/vnd.3gpp.pic-bw-small" }, - { "psd", "image/vnd.adobe.photoshop" }, - { "psf", "application/x-font-linux-psf" }, - { "pskcxml", "application/pskc+xml" }, - { "ptid", "application/vnd.pvi.ptid1" }, - { "pub", "application/x-mspublisher" }, - { "pvb", "application/vnd.3gpp.pic-bw-var" }, - { "pwn", "application/vnd.3m.post-it-notes" }, - { "pya", "audio/vnd.ms-playready.media.pya" }, - { "pyv", "video/vnd.ms-playready.media.pyv" }, - { "qam", "application/vnd.epson.quickanime" }, - { "qbo", "application/vnd.intu.qbo" }, - { "qfx", "application/vnd.intu.qfx" }, - { "qps", "application/vnd.publishare-delta-tree" }, - { "qt", "video/quicktime" }, - { "qwd", "application/vnd.quark.quarkxpress" }, - { "qwt", "application/vnd.quark.quarkxpress" }, - { "qxb", "application/vnd.quark.quarkxpress" }, - { "qxd", "application/vnd.quark.quarkxpress" }, - { "qxl", "application/vnd.quark.quarkxpress" }, - { "qxt", "application/vnd.quark.quarkxpress" }, - { "ra", "audio/x-pn-realaudio" }, - { "ram", "audio/x-pn-realaudio" }, - { "rar", "application/x-rar-compressed" }, - { "ras", "image/x-cmu-raster" }, - { "rcprofile", "application/vnd.ipunplugged.rcprofile" }, - { "rdf", "application/rdf+xml" }, - { "rdz", "application/vnd.data-vision.rdz" }, - { "rep", "application/vnd.businessobjects" }, - { "res", "application/x-dtbresource+xml" }, - { "rgb", "image/x-rgb" }, - { "rif", "application/reginfo+xml" }, - { "rip", "audio/vnd.rip" }, - { "ris", "application/x-research-info-systems" }, - { "rl", "application/resource-lists+xml" }, - { "rlc", "image/vnd.fujixerox.edmics-rlc" }, - { "rld", "application/resource-lists-diff+xml" }, - { "rm", "application/vnd.rn-realmedia" }, - { "rmi", "audio/midi" }, - { "rmp", "audio/x-pn-realaudio-plugin" }, - { "rms", "application/vnd.jcp.javame.midlet-rms" }, - { "rmvb", "application/vnd.rn-realmedia-vbr" }, - { "rnc", "application/relax-ng-compact-syntax" }, - { "roa", "application/rpki-roa" }, - { "roff", "text/troff" }, - { "rp9", "application/vnd.cloanto.rp9" }, - { "rpss", "application/vnd.nokia.radio-presets" }, - { "rpst", "application/vnd.nokia.radio-preset" }, - { "rq", "application/sparql-query" }, - { "rs", "application/rls-services+xml" }, - { "rsd", "application/rsd+xml" }, - { "rss", "application/rss+xml" }, - { "rtf", "application/rtf" }, - { "rtx", "text/richtext" }, - { "s", "text/x-asm" }, - { "s3m", "audio/s3m" }, - { "saf", "application/vnd.yamaha.smaf-audio" }, - { "sbml", "application/sbml+xml" }, - { "sc", "application/vnd.ibm.secure-container" }, - { "scd", "application/x-msschedule" }, - { "scm", "application/vnd.lotus-screencam" }, - { "scq", "application/scvp-cv-request" }, - { "scs", "application/scvp-cv-response" }, - { "scurl", "text/vnd.curl.scurl" }, - { "sda", "application/vnd.stardivision.draw" }, - { "sdc", "application/vnd.stardivision.calc" }, - { "sdd", "application/vnd.stardivision.impress" }, - { "sdkd", "application/vnd.solent.sdkm+xml" }, - { "sdkm", "application/vnd.solent.sdkm+xml" }, - { "sdp", "application/sdp" }, - { "sdw", "application/vnd.stardivision.writer" }, - { "see", "application/vnd.seemail" }, - { "seed", "application/vnd.fdsn.seed" }, - { "sema", "application/vnd.sema" }, - { "semd", "application/vnd.semd" }, - { "semf", "application/vnd.semf" }, - { "ser", "application/java-serialized-object" }, - { "setpay", "application/set-payment-initiation" }, - { "setreg", "application/set-registration-initiation" }, - { "sfd-hdstx", "application/vnd.hydrostatix.sof-data" }, - { "sfs", "application/vnd.spotfire.sfs" }, - { "sfv", "text/x-sfv" }, - { "sgi", "image/sgi" }, - { "sgl", "application/vnd.stardivision.writer-global" }, - { "sgm", "text/sgml" }, - { "sgml", "text/sgml" }, - { "sh", "application/x-sh" }, - { "shar", "application/x-shar" }, - { "shf", "application/shf+xml" }, - { "sid", "image/x-mrsid-image" }, - { "sig", "application/pgp-signature" }, - { "sil", "audio/silk" }, - { "silo", "model/mesh" }, - { "sis", "application/vnd.symbian.install" }, - { "sisx", "application/vnd.symbian.install" }, - { "sit", "application/x-stuffit" }, - { "sitx", "application/x-stuffitx" }, - { "skd", "application/vnd.koan" }, - { "skm", "application/vnd.koan" }, - { "skp", "application/vnd.koan" }, - { "skt", "application/vnd.koan" }, - { "sldm", "application/vnd.ms-powerpoint.slide.macroenabled.12" }, - { "sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide" }, - { "slt", "application/vnd.epson.salt" }, - { "sm", "application/vnd.stepmania.stepchart" }, - { "smf", "application/vnd.stardivision.math" }, - { "smi", "application/smil+xml" }, - { "smil", "application/smil+xml" }, - { "smv", "video/x-smv" }, - { "smzip", "application/vnd.stepmania.package" }, - { "snd", "audio/basic" }, - { "snf", "application/x-font-snf" }, - { "so", "application/octet-stream" }, - { "spc", "application/x-pkcs7-certificates" }, - { "spf", "application/vnd.yamaha.smaf-phrase" }, - { "spl", "application/x-futuresplash" }, - { "spot", "text/vnd.in3d.spot" }, - { "spp", "application/scvp-vp-response" }, - { "spq", "application/scvp-vp-request" }, - { "spx", "audio/ogg" }, - { "sql", "application/x-sql" }, - { "src", "application/x-wais-source" }, - { "srt", "application/x-subrip" }, - { "sru", "application/sru+xml" }, - { "srx", "application/sparql-results+xml" }, - { "ssdl", "application/ssdl+xml" }, - { "sse", "application/vnd.kodak-descriptor" }, - { "ssf", "application/vnd.epson.ssf" }, - { "ssml", "application/ssml+xml" }, - { "st", "application/vnd.sailingtracker.track" }, - { "stc", "application/vnd.sun.xml.calc.template" }, - { "std", "application/vnd.sun.xml.draw.template" }, - { "stf", "application/vnd.wt.stf" }, - { "sti", "application/vnd.sun.xml.impress.template" }, - { "stk", "application/hyperstudio" }, - { "stl", "application/vnd.ms-pki.stl" }, - { "str", "application/vnd.pg.format" }, - { "stw", "application/vnd.sun.xml.writer.template" }, - { "sub", "image/vnd.dvb.subtitle" }, - { "sus", "application/vnd.sus-calendar" }, - { "susp", "application/vnd.sus-calendar" }, - { "sv4cpio", "application/x-sv4cpio" }, - { "sv4crc", "application/x-sv4crc" }, - { "svc", "application/vnd.dvb.service" }, - { "svd", "application/vnd.svd" }, - { "svg", "image/svg+xml" }, - { "svgz", "image/svg+xml" }, - { "swa", "application/x-director" }, - { "swf", "application/x-shockwave-flash" }, - { "swi", "application/vnd.aristanetworks.swi" }, - { "sxc", "application/vnd.sun.xml.calc" }, - { "sxd", "application/vnd.sun.xml.draw" }, - { "sxg", "application/vnd.sun.xml.writer.global" }, - { "sxi", "application/vnd.sun.xml.impress" }, - { "sxm", "application/vnd.sun.xml.math" }, - { "sxw", "application/vnd.sun.xml.writer" }, - { "t", "text/troff" }, - { "t3", "application/x-t3vm-image" }, - { "taglet", "application/vnd.mynfc" }, - { "tao", "application/vnd.tao.intent-module-archive" }, - { "tar", "application/x-tar" }, - { "tcap", "application/vnd.3gpp2.tcap" }, - { "tcl", "application/x-tcl" }, - { "teacher", "application/vnd.smart.teacher" }, - { "tei", "application/tei+xml" }, - { "teicorpus", "application/tei+xml" }, - { "tex", "application/x-tex" }, - { "texi", "application/x-texinfo" }, - { "texinfo", "application/x-texinfo" }, - { "text", "text/plain" }, - { "tfi", "application/thraud+xml" }, - { "tfm", "application/x-tex-tfm" }, - { "tga", "image/x-tga" }, - { "thmx", "application/vnd.ms-officetheme" }, - { "tif", "image/tiff" }, - { "tiff", "image/tiff" }, - { "tmo", "application/vnd.tmobile-livetv" }, - { "torrent", "application/x-bittorrent" }, - { "tpl", "application/vnd.groove-tool-template" }, - { "tpt", "application/vnd.trid.tpt" }, - { "tr", "text/troff" }, - { "tra", "application/vnd.trueapp" }, - { "trm", "application/x-msterminal" }, - { "tsd", "application/timestamped-data" }, - { "tsv", "text/tab-separated-values" }, - { "ttc", "application/x-font-ttf" }, - { "ttf", "application/x-font-ttf" }, - { "ttl", "text/turtle" }, - { "twd", "application/vnd.simtech-mindmapper" }, - { "twds", "application/vnd.simtech-mindmapper" }, - { "txd", "application/vnd.genomatix.tuxedo" }, - { "txf", "application/vnd.mobius.txf" }, - { "txt", "text/plain" }, - { "u32", "application/x-authorware-bin" }, - { "udeb", "application/x-debian-package" }, - { "ufd", "application/vnd.ufdl" }, - { "ufdl", "application/vnd.ufdl" }, - { "ulx", "application/x-glulx" }, - { "umj", "application/vnd.umajin" }, - { "unityweb", "application/vnd.unity" }, - { "uoml", "application/vnd.uoml+xml" }, - { "uri", "text/uri-list" }, - { "uris", "text/uri-list" }, - { "urls", "text/uri-list" }, - { "ustar", "application/x-ustar" }, - { "utz", "application/vnd.uiq.theme" }, - { "uu", "text/x-uuencode" }, - { "uva", "audio/vnd.dece.audio" }, - { "uvd", "application/vnd.dece.data" }, - { "uvf", "application/vnd.dece.data" }, - { "uvg", "image/vnd.dece.graphic" }, - { "uvh", "video/vnd.dece.hd" }, - { "uvi", "image/vnd.dece.graphic" }, - { "uvm", "video/vnd.dece.mobile" }, - { "uvp", "video/vnd.dece.pd" }, - { "uvs", "video/vnd.dece.sd" }, - { "uvt", "application/vnd.dece.ttml+xml" }, - { "uvu", "video/vnd.uvvu.mp4" }, - { "uvv", "video/vnd.dece.video" }, - { "uvva", "audio/vnd.dece.audio" }, - { "uvvd", "application/vnd.dece.data" }, - { "uvvf", "application/vnd.dece.data" }, - { "uvvg", "image/vnd.dece.graphic" }, - { "uvvh", "video/vnd.dece.hd" }, - { "uvvi", "image/vnd.dece.graphic" }, - { "uvvm", "video/vnd.dece.mobile" }, - { "uvvp", "video/vnd.dece.pd" }, - { "uvvs", "video/vnd.dece.sd" }, - { "uvvt", "application/vnd.dece.ttml+xml" }, - { "uvvu", "video/vnd.uvvu.mp4" }, - { "uvvv", "video/vnd.dece.video" }, - { "uvvx", "application/vnd.dece.unspecified" }, - { "uvvz", "application/vnd.dece.zip" }, - { "uvx", "application/vnd.dece.unspecified" }, - { "uvz", "application/vnd.dece.zip" }, - { "vcard", "text/vcard" }, - { "vcd", "application/x-cdlink" }, - { "vcf", "text/x-vcard" }, - { "vcg", "application/vnd.groove-vcard" }, - { "vcs", "text/x-vcalendar" }, - { "vcx", "application/vnd.vcx" }, - { "vis", "application/vnd.visionary" }, - { "viv", "video/vnd.vivo" }, - { "vob", "video/x-ms-vob" }, - { "vor", "application/vnd.stardivision.writer" }, - { "vox", "application/x-authorware-bin" }, - { "vrml", "model/vrml" }, - { "vsd", "application/vnd.visio" }, - { "vsf", "application/vnd.vsf" }, - { "vss", "application/vnd.visio" }, - { "vst", "application/vnd.visio" }, - { "vsw", "application/vnd.visio" }, - { "vtu", "model/vnd.vtu" }, - { "vxml", "application/voicexml+xml" }, - { "w3d", "application/x-director" }, - { "wad", "application/x-doom" }, - { "wav", "audio/x-wav" }, - { "wax", "audio/x-ms-wax" }, - { "wbmp", "image/vnd.wap.wbmp" }, - { "wbs", "application/vnd.criticaltools.wbs+xml" }, - { "wbxml", "application/vnd.wap.wbxml" }, - { "wcm", "application/vnd.ms-works" }, - { "wdb", "application/vnd.ms-works" }, - { "wdp", "image/vnd.ms-photo" }, - { "weba", "audio/webm" }, - { "webm", "video/webm" }, - { "webp", "image/webp" }, - { "wg", "application/vnd.pmi.widget" }, - { "wgt", "application/widget" }, - { "wks", "application/vnd.ms-works" }, - { "wm", "video/x-ms-wm" }, - { "wma", "audio/x-ms-wma" }, - { "wmd", "application/x-ms-wmd" }, - { "wmf", "application/x-msmetafile" }, - { "wml", "text/vnd.wap.wml" }, - { "wmlc", "application/vnd.wap.wmlc" }, - { "wmls", "text/vnd.wap.wmlscript" }, - { "wmlsc", "application/vnd.wap.wmlscriptc" }, - { "wmv", "video/x-ms-wmv" }, - { "wmx", "video/x-ms-wmx" }, - { "wmz", "application/x-ms-wmz" }, - { "woff", "application/font-woff" }, - { "wpd", "application/vnd.wordperfect" }, - { "wpl", "application/vnd.ms-wpl" }, - { "wps", "application/vnd.ms-works" }, - { "wqd", "application/vnd.wqd" }, - { "wri", "application/x-mswrite" }, - { "wrl", "model/vrml" }, - { "wsdl", "application/wsdl+xml" }, - { "wspolicy", "application/wspolicy+xml" }, - { "wtb", "application/vnd.webturbo" }, - { "wvx", "video/x-ms-wvx" }, - { "x32", "application/x-authorware-bin" }, - { "x3d", "model/x3d+xml" }, - { "x3db", "model/x3d+binary" }, - { "x3dbz", "model/x3d+binary" }, - { "x3dv", "model/x3d+vrml" }, - { "x3dvz", "model/x3d+vrml" }, - { "x3dz", "model/x3d+xml" }, - { "xaml", "application/xaml+xml" }, - { "xap", "application/x-silverlight-app" }, - { "xar", "application/vnd.xara" }, - { "xbap", "application/x-ms-xbap" }, - { "xbd", "application/vnd.fujixerox.docuworks.binder" }, - { "xbm", "image/x-xbitmap" }, - { "xdf", "application/xcap-diff+xml" }, - { "xdm", "application/vnd.syncml.dm+xml" }, - { "xdp", "application/vnd.adobe.xdp+xml" }, - { "xdssc", "application/dssc+xml" }, - { "xdw", "application/vnd.fujixerox.docuworks" }, - { "xenc", "application/xenc+xml" }, - { "xer", "application/patch-ops-error+xml" }, - { "xfdf", "application/vnd.adobe.xfdf" }, - { "xfdl", "application/vnd.xfdl" }, - { "xht", "application/xhtml+xml" }, - { "xhtml", "application/xhtml+xml" }, - { "xhvml", "application/xv+xml" }, - { "xif", "image/vnd.xiff" }, - { "xla", "application/vnd.ms-excel" }, - { "xlam", "application/vnd.ms-excel.addin.macroenabled.12" }, - { "xlc", "application/vnd.ms-excel" }, - { "xlf", "application/x-xliff+xml" }, - { "xlm", "application/vnd.ms-excel" }, - { "xls", "application/vnd.ms-excel" }, - { "xlsb", "application/vnd.ms-excel.sheet.binary.macroenabled.12" }, - { "xlsm", "application/vnd.ms-excel.sheet.macroenabled.12" }, - { "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, - { "xlt", "application/vnd.ms-excel" }, - { "xltm", "application/vnd.ms-excel.template.macroenabled.12" }, - { "xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" }, - { "xlw", "application/vnd.ms-excel" }, - { "xm", "audio/xm" }, - { "xml", "application/xml" }, - { "xo", "application/vnd.olpc-sugar" }, - { "xop", "application/xop+xml" }, - { "xpi", "application/x-xpinstall" }, - { "xpl", "application/xproc+xml" }, - { "xpm", "image/x-xpixmap" }, - { "xpr", "application/vnd.is-xpr" }, - { "xps", "application/vnd.ms-xpsdocument" }, - { "xpw", "application/vnd.intercon.formnet" }, - { "xpx", "application/vnd.intercon.formnet" }, - { "xsl", "application/xml" }, - { "xslt", "application/xslt+xml" }, - { "xsm", "application/vnd.syncml+xml" }, - { "xspf", "application/xspf+xml" }, - { "xul", "application/vnd.mozilla.xul+xml" }, - { "xvm", "application/xv+xml" }, - { "xvml", "application/xv+xml" }, - { "xwd", "image/x-xwindowdump" }, - { "xyz", "chemical/x-xyz" }, - { "xz", "application/x-xz" }, - { "yang", "application/yang" }, - { "yin", "application/yin+xml" }, - { "z1", "application/x-zmachine" }, - { "z2", "application/x-zmachine" }, - { "z3", "application/x-zmachine" }, - { "z4", "application/x-zmachine" }, - { "z5", "application/x-zmachine" }, - { "z6", "application/x-zmachine" }, - { "z7", "application/x-zmachine" }, - { "z8", "application/x-zmachine" }, - { "zaz", "application/vnd.zzazz.deck+xml" }, - { "zip", "application/zip" }, - { "zir", "application/vnd.zul" }, - { "zirz", "application/vnd.zul" }, - { "zmm", "application/vnd.handheld-entertainment+xml" } - }; -} - diff --git a/SnapX.Core/Utils/Miscellaneous/PingHelper.cs b/SnapX.Core/Utils/Miscellaneous/PingHelper.cs index b1bd114c9..673a050c9 100644 --- a/SnapX.Core/Utils/Miscellaneous/PingHelper.cs +++ b/SnapX.Core/Utils/Miscellaneous/PingHelper.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/PingResult.cs b/SnapX.Core/Utils/Miscellaneous/PingResult.cs index 73abb0dfe..ccac2bcdb 100644 --- a/SnapX.Core/Utils/Miscellaneous/PingResult.cs +++ b/SnapX.Core/Utils/Miscellaneous/PingResult.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/ProxyInfo.cs b/SnapX.Core/Utils/Miscellaneous/ProxyInfo.cs index 0918093a1..906462a8a 100644 --- a/SnapX.Core/Utils/Miscellaneous/ProxyInfo.cs +++ b/SnapX.Core/Utils/Miscellaneous/ProxyInfo.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/SevenZipManager.cs b/SnapX.Core/Utils/Miscellaneous/SevenZipManager.cs index d53caa370..9b2d91c0b 100644 --- a/SnapX.Core/Utils/Miscellaneous/SevenZipManager.cs +++ b/SnapX.Core/Utils/Miscellaneous/SevenZipManager.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/Miscellaneous/StringLineReader.cs b/SnapX.Core/Utils/Miscellaneous/StringLineReader.cs deleted file mode 100644 index acf37397b..000000000 --- a/SnapX.Core/Utils/Miscellaneous/StringLineReader.cs +++ /dev/null @@ -1,67 +0,0 @@ - -// SPDX-License-Identifier: GPL-3.0-or-later - - -using System.Text; - -namespace SnapX.Core.Utils.Miscellaneous; - -public class StringLineReader -{ - public string Text { get; private set; } - public int Position { get; private set; } - public int Length { get; private set; } - - public StringLineReader(string text) - { - Text = text; - Length = Text.Length; - } - - public string ReadLine() - { - var builder = new StringBuilder(); - - while (!string.IsNullOrEmpty(Text) && Position < Length) - { - var ch = Text[Position]; - builder.Append(ch); - Position++; - - if (ch != '\r' && ch != '\n' && Position != Length) - { - return builder.ToString(); - } - - if (ch == '\r' && Position < Length && Text[Position] == '\n') - { - continue; - } - - return builder.ToString(); - } - - return null; - } - - public string[] ReadAllLines(bool autoTrim = true) - { - List lines = []; - - string line; - - while ((line = ReadLine()) != null) - { - if (autoTrim) line = line.Trim(); - lines.Add(line); - } - - return lines.ToArray(); - } - - public void Reset() - { - Position = 0; - } -} - diff --git a/SnapX.Core/Utils/Native/INativeAPI.cs b/SnapX.Core/Utils/Native/INativeAPI.cs new file mode 100644 index 000000000..256030773 --- /dev/null +++ b/SnapX.Core/Utils/Native/INativeAPI.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp; +using SnapX.Core.Media; + +namespace SnapX.Core.Utils.Native; + +// Secure, Contain, & Protect. +public interface INativeAPI +{ + void ShowWindow(WindowInfo windowInfo); + void ShowWindow(IntPtr hwnd); + Image GetJumboFileIcon(string filePath, bool jumboSize = true); + void HideWindow(WindowInfo windowInfo); + void HideWindow(IntPtr handle); + List GetWindowList(); + void CopyText(string text); + void CopyImage(Image image, string? fileName); + Rectangle GetWindowRectangle(WindowInfo window); + Rectangle GetWindowRectangle(IntPtr windowHandle); + Point GetCursorPosition(); + Screen? GetScreen(Point pos); +} diff --git a/SnapX.Core/Utils/Native/InputHelpers.cs b/SnapX.Core/Utils/Native/InputHelpers.cs deleted file mode 100644 index e47370d55..000000000 --- a/SnapX.Core/Utils/Native/InputHelpers.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace SnapX.Core.Utils.Native; - -public static class InputHelpers -{ - public static void SendKeyPress() - { - - } -} diff --git a/SnapX.Core/Utils/Native/LinuxAPI.cs b/SnapX.Core/Utils/Native/LinuxAPI.cs index 985cf9c28..b3d19f3c7 100644 --- a/SnapX.Core/Utils/Native/LinuxAPI.cs +++ b/SnapX.Core/Utils/Native/LinuxAPI.cs @@ -3,11 +3,12 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; +using SnapX.Core.Interfaces; using SnapX.Core.Media; namespace SnapX.Core.Utils.Native; -public partial class LinuxAPI : NativeAPI +public partial class LinuxAPI(ILoggerService Logger) : INativeAPI { private const string LibX11 = "libX11.so.6"; @@ -30,12 +31,17 @@ internal static bool IsGNOME() && sessionVersion.Contains("gnome", StringComparison.OrdinalIgnoreCase); } - public override Rectangle GetWindowRectangle(IntPtr windowHandle) + public Rectangle GetWindowRectangle(WindowInfo window) + { + return GetWindowRectangleX11(window.Handle); + } + + public Rectangle GetWindowRectangle(IntPtr windowHandle) { return GetWindowRectangleX11(windowHandle); } - public override Screen? GetScreen(Point pos) + public Screen? GetScreen(Point pos) { var display = XOpenDisplay(null); if (display == IntPtr.Zero) @@ -62,7 +68,7 @@ out _ if (pos.X < x || pos.X > x + (int)width || pos.Y < y || pos.Y > y + (int)height) continue; - DebugHelper.Logger?.Debug("Point {Pos} is within screen {I} bounds", pos, i); + Logger.Debug("Point {Pos} is within screen {I} bounds", pos, i); return new Screen() { Bounds = new Rectangle(x, y, (int)width, (int)height), @@ -75,22 +81,47 @@ out _ return null; } - public override List GetWindowList() + public void ShowWindow(WindowInfo windowInfo) + { + throw new NotImplementedException(); + } + + public void ShowWindow(IntPtr hwnd) + { + throw new NotImplementedException(); + } + + public Image GetJumboFileIcon(string filePath, bool jumboSize = true) + { + throw new NotImplementedException(); + } + + public void HideWindow(WindowInfo windowInfo) + { + throw new NotImplementedException(); + } + + public void HideWindow(IntPtr handle) + { + throw new NotImplementedException(); + } + + public List GetWindowList() { var windows = new List(); if (IsWayland()) { - if (IsPlasma()) - { - // Interact with Plasmashell over DBus - return windows; - } - - if (IsGNOME()) - { - // Interact with GNOME Shell - return windows; - } + // if (IsPlasma()) + // { + // // Interact with Plasmashell over DBus + // return windows; + // } + // + // if (IsGNOME()) + // { + // // Interact with GNOME Shell + // return windows; + // } return windows; } @@ -98,7 +129,7 @@ public override List GetWindowList() var display = XOpenDisplay(null); if (display == IntPtr.Zero) { - DebugHelper.Logger?.Debug("Unable to open X display"); + Logger.Debug("Unable to open X display"); return windows; } @@ -115,7 +146,7 @@ out var nchildren ); if (status == 0) { - DebugHelper.Logger?.Debug("XQueryTree failed"); + Logger.Debug("XQueryTree failed"); XCloseDisplay(display); return windows; } @@ -279,7 +310,7 @@ private static bool IsWindowMinimized(IntPtr display, IntPtr hwnd) private const long ALL_PLANES = -1; public const int ZPIXMAP = 2; - internal static Image TakeScreenshotWithX11(Screen screen) + internal Image TakeScreenshotWithX11(Screen screen) { unsafe { @@ -305,18 +336,18 @@ internal static Image TakeScreenshotWithX11(Screen screen) } XGetWindowAttributes(display, rootWindow, out var attributes); - DebugHelper.Logger?.Debug("x: {AttributesX}", attributes.x); - DebugHelper.Logger?.Debug("y: {AttributesY}", attributes.y); - DebugHelper.Logger?.Debug("width: {AttributesWidth}", attributes.width); - DebugHelper.Logger?.Debug("height: {AttributesHeight}", attributes.height); - DebugHelper.Logger?.Debug( + Logger.Debug("x: {AttributesX}", attributes.x); + Logger.Debug("y: {AttributesY}", attributes.y); + Logger.Debug("width: {AttributesWidth}", attributes.width); + Logger.Debug("height: {AttributesHeight}", attributes.height); + Logger.Debug( "border_width: {AttributesBorderWidth}", attributes.border_width ); - DebugHelper.Logger?.Debug("depth: {AttributesDepth}", attributes.depth); - DebugHelper.Logger?.Debug("visual: {AttributesVisual}", attributes.visual); - DebugHelper.Logger?.Debug("root: {AttributesRoot}", attributes.root); - DebugHelper.Logger?.Debug("colormap: {AttributesColormap}", attributes.colormap); + Logger.Debug("depth: {AttributesDepth}", attributes.depth); + Logger.Debug("visual: {AttributesVisual}", attributes.visual); + Logger.Debug("root: {AttributesRoot}", attributes.root); + Logger.Debug("colormap: {AttributesColormap}", attributes.colormap); var screenBounds = screen.Bounds; var imagePtr = XGetImage( @@ -345,8 +376,8 @@ internal static Image TakeScreenshotWithX11(Screen screen) // For simplicity, assuming a direct byte copy is feasible for common ZPIXMAP depths (e.g., 24 or 32 bits). var bytesPerPixel = xImage.depth / 8; var pixelDataSize = xImage.width * xImage.height * bytesPerPixel; - DebugHelper.Logger?.Debug("bytesPerPixel: {bytesPerPixel}", bytesPerPixel); - DebugHelper.Logger?.Debug("pixelDataSize: {pixelDataSize}", pixelDataSize); + Logger.Debug("bytesPerPixel: {BytesPerPixel}", bytesPerPixel); + Logger.Debug("pixelDataSize: {PixelDataSize}", pixelDataSize); // Create a byte array to hold the pixel data var pixelData = new byte[pixelDataSize]; @@ -529,7 +560,7 @@ public struct XSelectionRequestEvent // private static readonly IntPtr XA_PRIMARY = 1; internal const IntPtr XA_CLIPBOARD = 2; - public override void CopyText(string text) + public void CopyText(string text) { if (IsWayland()) { @@ -540,7 +571,7 @@ public override void CopyText(string text) var display = XOpenDisplay(null); if (display == IntPtr.Zero) { - DebugHelper.Logger?.Debug("Unable to open X11 display"); + Logger.Debug("Unable to open X11 display"); return; } var root = XDefaultRootWindow(display); @@ -621,7 +652,7 @@ public Rectangle GetScreenBounds() } } - public override void CopyImage(Image image, string? filename) + public void CopyImage(Image image, string? filename) { using var ms = new MemoryStream(); // Save the image in a format that ImageSharp understands for re-loading/processing @@ -635,7 +666,7 @@ public override void CopyImage(Image image, string? filename) if (IsWayland()) { - DebugHelper.Logger?.Debug("LinuxAPI.CopyImage - Wayland only code"); + Logger.Debug("LinuxAPI.CopyImage - Wayland only code"); // For Wayland, you'd need wl-clipboard or similar native Wayland protocols. // This X11 implementation does not apply to Wayland. // return; @@ -644,12 +675,12 @@ public override void CopyImage(Image image, string? filename) try { // Get the singleton instance of the clipboard handler and set the image - X11ClipboardHandler.Instance.SetImage(imageForClipboard, filename); - DebugHelper.Logger?.Debug("X11 image clipboard initiated."); + new X11ClipboardHandler(Logger).SetImage(imageForClipboard, filename); + Logger.Debug("X11 image clipboard initiated"); } catch (Exception ex) { - DebugHelper.Logger?.Error($"Failed to set X11 clipboard image: {ex.Message}"); + Logger.Error("Failed to set X11 clipboard image: {ExMessage}", ex.Message); } } @@ -659,13 +690,7 @@ private static Rectangle GetWindowRectangleX11(IntPtr windowHandle) if (display == IntPtr.Zero) throw new InvalidOperationException("Unable to open X11 display."); - var attributes = new XWindowAttributes(); - if (XGetWindowAttributes(display, windowHandle, out attributes) != 0) - { - return new Rectangle(attributes.x, attributes.y, attributes.width, attributes.height); - } - - throw new InvalidOperationException("Unable to get window attributes."); + return XGetWindowAttributes(display, windowHandle, out var attributes) != 0 ? new Rectangle(attributes.x, attributes.y, attributes.width, attributes.height) : throw new InvalidOperationException("Unable to get window attributes."); } [LibraryImport(LibX11)] @@ -681,9 +706,9 @@ internal static partial int XQueryPointer( out int mask ); - public override Point GetCursorPosition() + public Point GetCursorPosition() { - DebugHelper.Logger?.Debug("Get cursor position"); + Logger.Debug("Get cursor position"); var display = XOpenDisplay(null); if (display == IntPtr.Zero) { @@ -707,7 +732,7 @@ out var mask ); XCloseDisplay(display); - DebugHelper.Logger?.Debug( + Logger.Debug( "Cursor position: {RootX}, {RootY}, {WinX}, {WinY}, {Mask}", rootX, rootY, diff --git a/SnapX.Core/Utils/Native/MacOSAPI.cs b/SnapX.Core/Utils/Native/MacOSAPI.cs index 1c82e836a..d2a69bf7e 100644 --- a/SnapX.Core/Utils/Native/MacOSAPI.cs +++ b/SnapX.Core/Utils/Native/MacOSAPI.cs @@ -3,10 +3,11 @@ using System.Text.RegularExpressions; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Jpeg; +using SnapX.Core.Media; namespace SnapX.Core.Utils.Native; -public class MacOSAPI : NativeAPI +public partial class MacOSAPI : INativeAPI { private static string GenerateFastString(int length) { @@ -17,13 +18,12 @@ private static string GenerateFastString(int length) result[i] = chars[random.Next(chars.Length)]; return new string(result); } - public override void CopyImage(Image image) - { - CopyImage(image, GenerateFastString(8) + ".png"); - } + private const string CoreGraphics = "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics"; - public override void CopyImage(Image image, string? fileName) + + public void CopyImage(Image image, string? fileName) { + fileName ??= GenerateFastString(8) + ".png"; var tempPath = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(fileName)}.jpg"); image.Save(tempPath, new JpegEncoder()); var appleScript = $"set the clipboard to (read (POSIX file \"{tempPath}\") as JPEG picture)"; @@ -51,30 +51,65 @@ public override void CopyImage(Image image, string? fileName) File.Delete(tempPath); } + public Rectangle GetWindowRectangle(WindowInfo window) + { + throw new NotImplementedException(); + } + + public Rectangle GetWindowRectangle(IntPtr windowHandle) + { + throw new NotImplementedException(); + } + + + public void ShowWindow(WindowInfo windowInfo) + { + throw new NotImplementedException(); + } + + public void ShowWindow(IntPtr hwnd) + { + throw new NotImplementedException(); + } + + public Image GetJumboFileIcon(string filePath, bool jumboSize = true) + { + throw new NotImplementedException(); + } + + public void HideWindow(WindowInfo windowInfo) + { + throw new NotImplementedException(); + } - public override void CopyText(string text) + public void HideWindow(IntPtr handle) + { + throw new NotImplementedException(); + } + + public List GetWindowList() + { + throw new NotImplementedException(); + } + public void CopyText(string text) { // Escape quotes in the text to ensure AppleScript handles them correctly // 1. Escape double quotes by replacing `"` with `""` for AppleScript var escapedText = text.Replace("\"", "\"\""); - // 2. Escape backslashes by replacing `\` with `\\` (for C# string formatting) - escapedText = "\"" + Regex.Replace(escapedText, @"(\\+)$", @"$1$1") + "\""; ; + // 2. Escape backslashes by replacing `\` with `\\` + escapedText = "\"" + Regex.Replace(escapedText, @"(\\+)$", @"$1$1") + "\""; - // Properly format the AppleScript to set the clipboard var appleScript = $"set the clipboard to \"{escapedText}\""; - // Create the process to execute the AppleScript var process = new Process(); process.StartInfo.FileName = "osascript"; process.StartInfo.Arguments = $"-e \"{appleScript}\""; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.UseShellExecute = false; - // Start the process process.Start(); - // Wait for the process to finish process.WaitForExit(); } [StructLayout(LayoutKind.Sequential)] @@ -83,19 +118,23 @@ struct CGPoint public double X; public double Y; } + [LibraryImport(CoreGraphics)] + private static partial CGPoint CGEventGetLocation(IntPtr eventRef); - [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")] - static extern CGPoint CGEventGetLocation(IntPtr eventRef); - - [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")] - static extern IntPtr CGEventCreate(IntPtr source); - [DllImport("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics")] - static extern IntPtr CFRelease(IntPtr eventRef); - public override Point GetCursorPosition() + [LibraryImport(CoreGraphics)] + private static partial IntPtr CGEventCreate(IntPtr source); + [LibraryImport(CoreGraphics)] + private static partial void CFRelease(IntPtr eventRef); + public Point GetCursorPosition() { var ev = CGEventCreate(IntPtr.Zero); var point = CGEventGetLocation(ev); CFRelease(ev); return new Point((int)point.X, (int)point.Y); } + + public Screen? GetScreen(Point pos) + { + throw new NotImplementedException(); + } } diff --git a/SnapX.Core/Utils/Native/Methods.cs b/SnapX.Core/Utils/Native/Methods.cs index 3e7f0726e..40c322ac7 100644 --- a/SnapX.Core/Utils/Native/Methods.cs +++ b/SnapX.Core/Utils/Native/Methods.cs @@ -1,23 +1,26 @@ using SixLabors.ImageSharp; +using SnapX.Core.Interfaces; using SnapX.Core.Media; using SnapX.Core.SharpCapture; using SnapX.Core.SharpCapture.Linux; using SnapX.Core.SharpCapture.macOS; +using SnapX.Core.Utils.Extensions; #if TARGET_WINDOWS using SnapX.Core.SharpCapture.Windows; #endif namespace SnapX.Core.Utils.Native; -public static class Methods +public class Methods(ILoggerService _logger) { + private ILoggerService Logger => _logger; private static bool IsMacOS => OperatingSystem.IsMacOS(); private static bool IsLinux => OperatingSystem.IsLinux(); private static bool IsWindows => OperatingSystem.IsWindows(); private static bool IsFreeBSD => OperatingSystem.IsFreeBSD(); - internal static NativeAPI NativeAPI + internal static INativeAPI NativeAPI { get { @@ -25,12 +28,12 @@ internal static NativeAPI NativeAPI return new WindowsAPI(); #else if (IsMacOS) return new MacOSAPI(); - if (IsLinux || IsFreeBSD) return new LinuxAPI(); + if (IsLinux || IsFreeBSD) return new LinuxAPI(DebugHelper.Logger as ILoggerService); throw new PlatformNotSupportedException("This platform is not supported for native API calls."); #endif } } - private static BaseCapture SharpCapture + private static BaseSharpCapture SharpCapture { get { @@ -44,7 +47,6 @@ private static BaseCapture SharpCapture } } public static List GetWindowList() => NativeAPI.GetWindowList(); - public static Image GetJumboFileIcon(string filePath, bool jumboSize = true) => NativeAPI.GetJumboFileIcon(filePath, jumboSize); public static void ShowWindow(WindowInfo window) => NativeAPI.ShowWindow(window); @@ -75,7 +77,7 @@ public static Point GetCursorPosition() } catch (Exception ex) { - DebugHelper.Logger.Warning(ex.ToString()); + ex.ShowError(); } DebugHelper.WriteLine($"GetCursorPosition returned {point}"); return point; diff --git a/SnapX.Core/Utils/Native/NativeAPI.cs b/SnapX.Core/Utils/Native/NativeAPI.cs deleted file mode 100644 index 5107f4465..000000000 --- a/SnapX.Core/Utils/Native/NativeAPI.cs +++ /dev/null @@ -1,25 +0,0 @@ -using SixLabors.ImageSharp; -using SnapX.Core.Media; - -namespace SnapX.Core.Utils.Native; - -// Secure, Contain, & Protect. -public class NativeAPI -{ - public virtual void ShowWindow(WindowInfo windowInfo) => throw new NotImplementedException("NativeAPI.ShowWindow is not implemented."); - - public virtual void ShowWindow(IntPtr hwnd) => throw new NotImplementedException("NativeAPI.ShowWindow is not implemented."); - public virtual Image GetJumboFileIcon(string filePath, bool jumboSize = true) => throw new NotImplementedException("NativeAPI.GetJumboFileIcon is not implemented."); - public virtual void HideWindow(WindowInfo windowInfo) => throw new NotImplementedException("NativeAPI.HideWindow is not implemented."); - public virtual List GetWindowList() => throw new NotImplementedException("NativeAPI.GetWindowList is not implemented."); - public virtual void HideWindow(IntPtr handle) => throw new NotImplementedException("NativeAPI.HideWindow is not implemented."); - public virtual void CopyText(string text) => throw new NotImplementedException("NativeAPI.CopyText is not implemented."); - public virtual void CopyImage(Image image) => CopyImage(image, "image.png"); // this could will never run - - public virtual void CopyImage(Image image, string? fileName) => throw new NotImplementedException("NativeAPI.CopyImage is not implemented."); - public virtual Rectangle GetWindowRectangle(WindowInfo window) => throw new NotImplementedException("NativeAPI.GetWindowRect is not implemented."); - public virtual Rectangle GetWindowRectangle(IntPtr windowHandle) => throw new NotImplementedException("NativeAPI.GetWindowRect is not implemented."); - public virtual Point GetCursorPosition() => throw new NotImplementedException("NativeAPI.GetCursorPosition is not implemented."); - public virtual Screen? GetScreen(Point pos) => - throw new NotImplementedException("NativeAPI.GetScreen is not implemented"); -} diff --git a/SnapX.Core/Utils/Native/WindowsAPI.cs b/SnapX.Core/Utils/Native/WindowsAPI.cs index 783f2aaee..bf4471c59 100644 --- a/SnapX.Core/Utils/Native/WindowsAPI.cs +++ b/SnapX.Core/Utils/Native/WindowsAPI.cs @@ -19,14 +19,14 @@ namespace SnapX.Core.Utils.Native; // Windows 10 version 1903 [SupportedOSPlatform("windows10.0.18362")] -public class WindowsAPI : NativeAPI +public class WindowsAPI : INativeAPI { // Constants for allocating memory and setting data format public const uint CF_TEXT = 1; private const uint CF_DIB = 8; private const uint CF_HDROP = 15; - public override void ShowWindow(WindowInfo Window) + public void ShowWindow(WindowInfo Window) { var handle = Window.Handle; if (handle == IntPtr.Zero) @@ -37,7 +37,7 @@ public override void ShowWindow(WindowInfo Window) PInvoke.ShowWindow(new HWND(handle), SHOW_WINDOW_CMD.SW_SHOW); } - public override void ShowWindow(IntPtr hwnd) + public void ShowWindow(IntPtr hwnd) { if (hwnd == IntPtr.Zero) { @@ -47,6 +47,21 @@ public override void ShowWindow(IntPtr hwnd) PInvoke.ShowWindow(new HWND(hwnd), SHOW_WINDOW_CMD.SW_SHOW); } + public Image GetJumboFileIcon(string filePath, bool jumboSize = true) + { + throw new NotImplementedException(); + } + + public void HideWindow(WindowInfo windowInfo) + { + throw new NotImplementedException(); + } + + public void HideWindow(IntPtr handle) + { + throw new NotImplementedException(); + } + // Method to check if a window is minimized public static bool IsWindowMinimized(IntPtr hwnd) { @@ -99,7 +114,7 @@ private static BOOL EnumWindowsCallback(HWND hwnd, LPARAM lParam) private static List windowList = []; - public override List GetWindowList() + public List GetWindowList() { windowList.Clear(); unsafe @@ -114,7 +129,7 @@ public override List GetWindowList() return windowList; } - public override void CopyText(string text) + public void CopyText(string text) { if (!PInvoke.OpenClipboard(new HWND())) { @@ -142,12 +157,23 @@ public override void CopyText(string text) } } - public override Point GetCursorPosition() + public Rectangle GetWindowRectangle(IntPtr windowHandle) + { + throw new NotImplementedException(); + } + + public Point GetCursorPosition() { PInvoke.GetCursorPos(out var LpPoint); return new Point(LpPoint.X, LpPoint.Y); } - public override void CopyImage(Image image, string? filename = null) + + public Screen? GetScreen(Point pos) + { + throw new NotImplementedException(); + } + + public void CopyImage(Image image, string? filename = null) { PInvoke.OpenClipboard(new HWND()); PInvoke.EmptyClipboard(); @@ -202,7 +228,7 @@ public override void CopyImage(Image image, string? filename = null) } } - public override Rectangle GetWindowRectangle(WindowInfo Window) + public Rectangle GetWindowRectangle(WindowInfo Window) { var handle = Window.Handle; if (handle == IntPtr.Zero) diff --git a/SnapX.Core/Utils/Native/X11ClipboardHandler.cs b/SnapX.Core/Utils/Native/X11ClipboardHandler.cs index a08e4ea6f..505b2d0e1 100644 --- a/SnapX.Core/Utils/Native/X11ClipboardHandler.cs +++ b/SnapX.Core/Utils/Native/X11ClipboardHandler.cs @@ -2,14 +2,14 @@ using System.Text; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; +using SnapX.Core.Interfaces; namespace SnapX.Core.Utils.Native; public class X11ClipboardHandler : IDisposable { - private static X11ClipboardHandler? _instance; private static readonly Lock _lock = new(); - + private readonly ILoggerService Logger; private IntPtr _display; private IntPtr _clipboardWindow; private Thread? _eventThread; @@ -25,16 +25,16 @@ public class X11ClipboardHandler : IDisposable private Image? _currentImage; private string? _currentFilename; - private X11ClipboardHandler() + public X11ClipboardHandler(ILoggerService Logger) { _display = LinuxAPI.XOpenDisplay(null); if (_display == IntPtr.Zero) { - throw new Exception("Unable to open X11 display for clipboard handler."); + throw new Exception("Unable to open X11 display for clipboard handler"); } - _clipboardWindow = LinuxAPI.XCreateSimpleWindow(_display, LinuxAPI.XDefaultRootWindow(_display), - 0, 0, 1, 1, 0, 0, 0); + _clipboardWindow = LinuxAPI.XCreateSimpleWindow(_display, LinuxAPI.XDefaultRootWindow(_display), 0, 0, 1, 1, 0, 0, 0); + this.Logger = Logger; LinuxAPI.XSelectInput(_display, _clipboardWindow, LinuxAPI.SelectionClearMask | LinuxAPI.SelectionRequestMask); @@ -48,19 +48,7 @@ private X11ClipboardHandler() }; _eventThread.Start(); - DebugHelper.Logger?.Debug("X11ClipboardHandler initialized and event loop started."); - } - - public static X11ClipboardHandler Instance - { - get - { - lock (_lock) - { - _instance ??= new X11ClipboardHandler(); - return _instance; - } - } + Logger.Debug("X11ClipboardHandler initialized and event loop started"); } private void InitializeAtoms() @@ -85,11 +73,11 @@ public void SetImage(Image image, string? filename = null) var owner = LinuxAPI.XGetSelectionOwner(_display, _atomClipboard); if (owner == _clipboardWindow) { - DebugHelper.Logger?.Debug($"Successfully claimed X11 CLIPBOARD ownership for image and filename '{_currentFilename}'."); + Logger.Debug("Successfully claimed X11 CLIPBOARD ownership for image and filename \'{CurrentFilename}\'", _currentFilename); } else { - DebugHelper.Logger?.Warning("Failed to claim X11 CLIPBOARD ownership. Another application might be the owner."); + Logger.Warning("Failed to claim X11 CLIPBOARD ownership. Another application might be the owner"); } } } @@ -114,16 +102,14 @@ private void EventLoop(CancellationToken cancellationToken) case LinuxAPI.SelectionClear: HandleSelectionClear(eventData.xselectionclear); break; - default: - break; } } - DebugHelper.Logger?.Debug("X11ClipboardHandler event loop terminated."); + Logger.Debug("X11ClipboardHandler event loop terminated"); } private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) { - DebugHelper.Logger?.Debug($"SelectionRequest received: Target {GetAtomName(request.target)}"); + Logger.Debug("SelectionRequest received: Target {AtomName}", GetAtomName(request.target)); var property = request.property; var type = IntPtr.Zero; @@ -135,20 +121,20 @@ private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) { if (request.selection != _atomClipboard) { - DebugHelper.Logger?.Debug("Selection request for non-CLIPBOARD selection ignored."); + Logger.Debug("Selection request for non-CLIPBOARD selection ignored"); return; } if (_currentImage == null) { - DebugHelper.Logger?.Warning("Selection request received but no image is set."); + Logger.Warning("Selection request received but no image is set"); property = IntPtr.Zero; type = IntPtr.Zero; } else if (request.target == _atomTargets) { - DebugHelper.Logger?.Debug("Responding to TARGETS request."); - IntPtr[] supportedTargets = { _atomTargets, _atomPng, _atomImagePng, _atomUtf8String }; + Logger.Debug("Responding to TARGETS request"); + IntPtr[] supportedTargets = [_atomTargets, _atomPng, _atomImagePng, _atomUtf8String]; data = new byte[supportedTargets.Length * Marshal.SizeOf()]; for (int i = 0; i < supportedTargets.Length; i++) { @@ -160,7 +146,7 @@ private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) } else if (request.target == _atomPng || request.target == _atomImagePng) { - DebugHelper.Logger?.Debug($"Responding to image/png request. Image dimensions: {_currentImage.Width}x{_currentImage.Height}"); + Logger.Debug("Responding to image/png request. Image dimensions: {Width}x{Height}", _currentImage.Width, _currentImage.Height); using var ms = new MemoryStream(); _currentImage.Save(ms, new PngEncoder()); data = ms.ToArray(); @@ -170,7 +156,7 @@ private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) } else if (request.target == _atomUtf8String && !string.IsNullOrEmpty(_currentFilename)) { - DebugHelper.Logger?.Debug("Responding to UTF8_STRING request (filename)."); + Logger.Debug("Responding to UTF8_STRING request (filename)"); data = Encoding.UTF8.GetBytes(_currentFilename); type = _atomUtf8String; format = 8; @@ -178,7 +164,7 @@ private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) } else { - DebugHelper.Logger?.Debug($"Unsupported selection target: {GetAtomName(request.target)}."); + Logger.Debug("Unsupported selection target: {AtomName}", GetAtomName(request.target)); property = IntPtr.Zero; type = IntPtr.Zero; } @@ -186,17 +172,17 @@ private void HandleSelectionRequest(LinuxAPI.XSelectionRequestEvent request) if (property != IntPtr.Zero && data != null) { LinuxAPI.XChangeProperty(_display, request.requestor, property, type, format, LinuxAPI.PropModeReplace, data, nElements); - DebugHelper.Logger?.Debug($"XChangeProperty successful for target {GetAtomName(request.target)}."); + Logger.Debug("XChangeProperty successful for target {AtomName}", GetAtomName(request.target)); } else if (property != IntPtr.Zero && data == null) { - DebugHelper.Logger?.Debug($"No data to provide for target {GetAtomName(request.target)}, setting property to None."); + Logger.Debug("No data to provide for target {AtomName}, setting property to None", GetAtomName(request.target)); property = IntPtr.Zero; } } catch (Exception ex) { - DebugHelper.Logger?.Error($"Error handling SelectionRequest: {ex.Message}"); + Logger.Error("Error handling SelectionRequest: {ExMessage}", ex.Message); property = IntPtr.Zero; } finally @@ -231,11 +217,11 @@ private void SendSelectionNotify(IntPtr requestor, IntPtr selection, IntPtr targ if (status == 0) { - DebugHelper.Logger?.Warning("XSendEvent for SelectionNotify failed."); + Logger.Warning("XSendEvent for SelectionNotify failed"); } else { - DebugHelper.Logger?.Debug($"SelectionNotify sent to {requestor} (property: {GetAtomName(property)})."); + Logger.Debug("SelectionNotify sent to {Requestor} (property: {AtomName})", requestor, GetAtomName(property)); } } finally @@ -248,7 +234,7 @@ private void HandleSelectionClear(LinuxAPI.XSelectionClearEvent clear) { if (clear.selection == _atomClipboard) { - DebugHelper.Logger?.Debug("CLIPBOARD ownership lost (SelectionClear event)."); + Logger.Debug("CLIPBOARD ownership lost (SelectionClear event)"); lock (_lock) { _currentImage = null; @@ -269,7 +255,7 @@ private string GetAtomName(IntPtr atom) public void Dispose() { - DebugHelper.Logger?.Debug("Disposing X11ClipboardHandler."); + Logger.Debug("Disposing X11ClipboardHandler"); _cts.Cancel(); _eventThread?.Join(); @@ -278,11 +264,9 @@ public void Dispose() LinuxAPI.XDestroyWindow(_display, _clipboardWindow); _clipboardWindow = IntPtr.Zero; } - if (_display != IntPtr.Zero) - { - LinuxAPI.XCloseDisplay(_display); - _display = IntPtr.Zero; - } - _instance = null; + + if (_display == IntPtr.Zero) return; + LinuxAPI.XCloseDisplay(_display); + _display = IntPtr.Zero; } } diff --git a/SnapX.Core/Utils/Parsers/CodeMenuEntry.cs b/SnapX.Core/Utils/Parsers/CodeMenuEntry.cs index a832d3184..666be06a8 100644 --- a/SnapX.Core/Utils/Parsers/CodeMenuEntry.cs +++ b/SnapX.Core/Utils/Parsers/CodeMenuEntry.cs @@ -1,23 +1,11 @@ - // SPDX-License-Identifier: GPL-3.0-or-later namespace SnapX.Core.Utils.Parsers; -public abstract class CodeMenuEntry +public abstract class CodeMenuEntry(string Value, string Description, string? Category = null) { protected abstract string Prefix { get; } - public string Value { get; private set; } - public string Description { get; private set; } - public string Category { get; private set; } - - public CodeMenuEntry(string value, string description, string category = null) - { - Value = value; - Description = description; - Category = category; - } - public string ToPrefixString() { return ToPrefixString(Prefix); diff --git a/SnapX.Core/Utils/Parsers/CodeMenuEntryActions.cs b/SnapX.Core/Utils/Parsers/CodeMenuEntryActions.cs index ca9bf211a..38a28eda2 100644 --- a/SnapX.Core/Utils/Parsers/CodeMenuEntryActions.cs +++ b/SnapX.Core/Utils/Parsers/CodeMenuEntryActions.cs @@ -1,16 +1,12 @@ namespace SnapX.Core.Utils.Parsers; -public class CodeMenuEntryActions : CodeMenuEntry +public class CodeMenuEntryActions(string Value, string Description) : CodeMenuEntry(Value, Description) { protected override string Prefix { get; } = "$"; public static readonly CodeMenuEntryActions input = new("input", "File path"); public static readonly CodeMenuEntryActions output = new("output", "File path with output file name extension"); - public CodeMenuEntryActions(string value, string description) : base(value, description) - { - } - public static string Parse(string pattern, string inputPath, string outputPath) { var result = pattern; diff --git a/SnapX.Core/Utils/Parsers/CodeMenuEntryFilename.cs b/SnapX.Core/Utils/Parsers/CodeMenuEntryFilename.cs index 549d13506..9507f9990 100644 --- a/SnapX.Core/Utils/Parsers/CodeMenuEntryFilename.cs +++ b/SnapX.Core/Utils/Parsers/CodeMenuEntryFilename.cs @@ -1,6 +1,7 @@ namespace SnapX.Core.Utils.Parsers; -public class CodeMenuEntryFilename : CodeMenuEntry +public class CodeMenuEntryFilename(string Value, string Description, string Category = null) + : CodeMenuEntry(Value, Description, Category) { protected override string Prefix => "%"; @@ -38,9 +39,5 @@ public class CodeMenuEntryFilename : CodeMenuEntry public static readonly CodeMenuEntryFilename uln = new("uln", "User login name", "Computer"); public static readonly CodeMenuEntryFilename cn = new("cn", "Computer name/HOSTNAME", "Computer"); public static readonly CodeMenuEntryFilename n = new("n", "New line"); - - public CodeMenuEntryFilename(string value, string description, string category = null) : base(value, description, category) - { - } } diff --git a/SnapX.Core/Utils/Parsers/CodeMenuEntryPixelInfo.cs b/SnapX.Core/Utils/Parsers/CodeMenuEntryPixelInfo.cs index b93c80135..ddb552dbd 100644 --- a/SnapX.Core/Utils/Parsers/CodeMenuEntryPixelInfo.cs +++ b/SnapX.Core/Utils/Parsers/CodeMenuEntryPixelInfo.cs @@ -4,7 +4,7 @@ namespace SnapX.Core.Utils.Parsers; -public class CodeMenuEntryPixelInfo : CodeMenuEntry +public class CodeMenuEntryPixelInfo(string Value, string Description) : CodeMenuEntry(Value, Description) { protected override string Prefix { get; } = "$"; @@ -36,10 +36,6 @@ public class CodeMenuEntryPixelInfo : CodeMenuEntry public static readonly CodeMenuEntryPixelInfo y = new("y", "Y position"); public static readonly CodeMenuEntryPixelInfo n = new("n", "New line"); - public CodeMenuEntryPixelInfo(string value, string description) : base(value, description) - { - } - public static string Parse(string input, Rgba64 color, Point position) { input = input.Replace(r255.ToPrefixString(), color.R.ToString(), StringComparison.InvariantCultureIgnoreCase). diff --git a/SnapX.Core/Utils/Parsers/NameParser.cs b/SnapX.Core/Utils/Parsers/NameParser.cs index a84be9f87..491cd1d10 100644 --- a/SnapX.Core/Utils/Parsers/NameParser.cs +++ b/SnapX.Core/Utils/Parsers/NameParser.cs @@ -107,14 +107,7 @@ public NameParser(NameParserType nameParserType) string hour; - if (sb.ToString().Contains(CodeMenuEntryFilename.pm.ToPrefixString())) - { - hour = Helpers.HourTo12(dt.Hour); - } - else - { - hour = Helpers.AddZeroes(dt.Hour); - } + hour = sb.ToString().Contains(CodeMenuEntryFilename.pm.ToPrefixString()) ? Helpers.HourTo12(dt.Hour) : Helpers.AddZeroes(dt.Hour); sb.Replace(CodeMenuEntryFilename.h.ToPrefixString(), hour) .Replace(CodeMenuEntryFilename.mi.ToPrefixString(), Helpers.AddZeroes(dt.Minute)) diff --git a/SnapX.Core/Utils/Random/RandomCrypto.cs b/SnapX.Core/Utils/Random/RandomCrypto.cs index 105b2e063..55868a70c 100644 --- a/SnapX.Core/Utils/Random/RandomCrypto.cs +++ b/SnapX.Core/Utils/Random/RandomCrypto.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -9,8 +8,8 @@ namespace SnapX.Core.Utils.Random; // https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom public static class RandomCrypto { - private static readonly object randomLock = new object(); - private static byte[] uint32Buffer = new byte[4]; + private static readonly Lock randomLock = new(); + private static readonly byte[] uint32Buffer = new byte[4]; /// Returns a non-negative random integer. /// A 32-bit signed integer that is greater than or equal to 0 and less than System.Int32.MaxValue. diff --git a/SnapX.Core/Utils/Random/RandomFast.cs b/SnapX.Core/Utils/Random/RandomFast.cs index 79b81c3cc..563e8c000 100644 --- a/SnapX.Core/Utils/Random/RandomFast.cs +++ b/SnapX.Core/Utils/Random/RandomFast.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,8 +5,8 @@ namespace SnapX.Core.Utils.Random; public static class RandomFast { - private static readonly object randomLock = new object(); - private static readonly System.Random random = new System.Random(); + private static readonly Lock randomLock = new(); + private static readonly System.Random random = new(); /// Returns a non-negative random integer. /// A 32-bit signed integer that is greater than or equal to 0 and less than System.Int32.MaxValue. diff --git a/SnapX.Core/Utils/URLHelpers.cs b/SnapX.Core/Utils/URLHelpers.cs index 19a93ae3a..eafc375e8 100644 --- a/SnapX.Core/Utils/URLHelpers.cs +++ b/SnapX.Core/Utils/URLHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/Utils/WebHelpers.cs b/SnapX.Core/Utils/WebHelpers.cs index 351d5e379..d0891b3b9 100644 --- a/SnapX.Core/Utils/WebHelpers.cs +++ b/SnapX.Core/Utils/WebHelpers.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later @@ -26,7 +25,7 @@ public static async Task DownloadFileAsync(string url, string? filePath) if (!responseMessage.IsSuccessStatusCode) { - DebugHelper.Logger.Error("{url}: {responseMessage.ReasonPhrase}", url, responseMessage); + DebugHelper.Logger?.Error("{Url}: {ResponseMessageReasonPhrase}", url, responseMessage); return; } @@ -55,14 +54,14 @@ public static async Task DataURLToImage(string? url) var base64Data = match.Groups["data"].Value; - byte[] imageBytes = Convert.FromBase64String(base64Data); + var imageBytes = Convert.FromBase64String(base64Data); using var ms = new MemoryStream(imageBytes); var image = await Image.LoadAsync(ms); return image; } - public static async Task DownloadStringAsync(string url) + public static async Task DownloadStringAsync(string url) { if (string.IsNullOrEmpty(url)) { @@ -71,13 +70,10 @@ public static async Task DownloadStringAsync(string url) var client = HttpClientFactory.Get(); using var responseMessage = await client.GetAsync(url); - if (!responseMessage.IsSuccessStatusCode) - { - DebugHelper.Logger.Error("{url}: {responseMessage.ReasonPhrase}", url, responseMessage); - return null; - } + if (responseMessage.IsSuccessStatusCode) return await responseMessage.Content.ReadAsStringAsync(); + DebugHelper.Logger?.Error("{Url}: {ResponseMessageReasonPhrase}", url, responseMessage); + return null; - return await responseMessage.Content.ReadAsStringAsync(); } @@ -95,7 +91,7 @@ public static async Task DownloadStringAsync(string url) } - public static async Task DownloadImageAsync(string? url) + public static async Task DownloadImageAsync(string? url) { if (string.IsNullOrEmpty(url)) return null; @@ -109,13 +105,13 @@ public static async Task DownloadImageAsync(string? url) return null; } - var mediaType = responseMessage.Content.Headers.ContentType.MediaType; + var mediaType = responseMessage.Content.Headers.ContentType?.MediaType; if (mediaType == null) { - DebugHelper.Logger.Error("{url}: mediaType is null.", url); + DebugHelper.Logger?.Error("{Url}: mediaType is null", url); return null; } - if (!MimeTypesPlus.IsImageMimeType(mediaType)) + if (!mediaType.Contains("image/")) return null; var data = await responseMessage.Content.ReadAsByteArrayAsync(); @@ -127,7 +123,7 @@ public static async Task DownloadImageAsync(string? url) } catch (Exception ex) { - DebugHelper.Logger.Error("{url}: {message}", url, ex.Message); + DebugHelper.Logger?.Error("{Url}: {Message}", url, ex.Message); DebugHelper.WriteException(ex); return null; } diff --git a/SnapX.Core/VersionEnforcer.cs b/SnapX.Core/VersionEnforcer.cs index 411b6f5c1..aa0f7b17f 100644 --- a/SnapX.Core/VersionEnforcer.cs +++ b/SnapX.Core/VersionEnforcer.cs @@ -3,43 +3,45 @@ using System.Text; using System.Text.Json; using System.Text.Json.Serialization; +using SnapX.Core.Interfaces; namespace SnapX.Core; -// I might've lost my marbles working on this class. -// Sorry for the bad code, but, it works! - [JsonSerializable(typeof(VersionEnforcer.LockFileContent))] internal sealed partial class VersionEnforcerContext : JsonSerializerContext; public sealed class VersionEnforcer : IDisposable { + private ILoggerService _logger; private readonly string _lockFilePath; private FileStream? _lockFileStream; private readonly string _currentVersion; private readonly int _currentPID; private readonly bool _startupFailed; private bool _ownsLockFile; + internal record LockFileContent { - public int ProcessId { get; set; } - public string Version { get; set; } + public required int ProcessId { get; set; } + public required string Version { get; set; } } - public VersionEnforcer(string lockDirectory) + public VersionEnforcer(string lockDirectory, ILoggerService logger) { if (string.IsNullOrWhiteSpace(lockDirectory)) { - throw new ArgumentException("Lock directory cannot be null or empty.", nameof(lockDirectory)); + throw new ArgumentException($"Lock directory cannot be null or empty {nameof(lockDirectory)}"); } + _logger = logger; + try { Directory.CreateDirectory(lockDirectory); } catch (Exception ex) { - DebugHelper.WriteLine($"VersionEnforcer failed to create lock directory '{lockDirectory}' . Skipping version lock checks. Good luck."); - DebugHelper.WriteException(ex); + _logger.Information("VersionEnforcer failed to create lock directory \'{LockDirectory}\' . Skipping version lock checks. Good luck", lockDirectory); + _logger.Error(ex.ToString()); _startupFailed = true; } @@ -135,7 +137,7 @@ private void HandleExistingVersion(LockFileContent? lockFileInfo, string existin var statement = !isPreviousInstanceRunning ? $"Took ownership from previous dead instance (same version, PID: {previousInstance})" : $"An existing instance (same version, PID: {lockFileInfo?.ProcessId}) was detected. This is supported. :)"; - DebugHelper.WriteLine($"Application (Version: {_currentVersion}) started. {statement}"); + _logger.Information("Application (Version: {CurrentVersion}) started. {Statement}", _currentVersion, statement); } private void HandleNoExistingVersion(ref LockFileContent? lockFileInfo) @@ -147,14 +149,12 @@ private void HandleNoExistingVersion(ref LockFileContent? lockFileInfo) }; _ownsLockFile = true; WriteVersionInfoToLockFile(lockFileInfo); - DebugHelper.WriteLine( - $"Application (Version: {_currentVersion}) started. First instance of this version (or lock file was empty)."); + _logger.Information("Application (Version: {CurrentVersion}) started. First instance of this version (or lock file was empty)", _currentVersion); } private void HandleLockFileInUse() { - DebugHelper.WriteLine( - $"Application (Version: {_currentVersion}) detected another instance running which holds the lock. This instance will try to read its version."); + _logger.Information("Application (Version: {CurrentVersion}) detected another instance running which holds the lock. This instance will try to read its version", _currentVersion); try { @@ -187,8 +187,7 @@ private void HandleLockFileInUse() } if (lockFileInfo?.ProcessId == _currentPID) _ownsLockFile = true; - DebugHelper.WriteLine( - $"Application Lock (Version: {_currentVersion}) is compatible with the running instance (same version). Running alongside."); + _logger.Information("Application Lock (Version: {CurrentVersion}) is compatible with the running instance (same version). Running alongside", _currentVersion); } catch (Exception innerEx) { @@ -221,7 +220,7 @@ private void HandleLockFileInUse() } catch (Exception ex) { - DebugHelper.WriteLine($"VersionLock failed to parse/deserialize LockFile at {_lockFilePath}. Nuking file from orbit."); + _logger.Information("VersionLock failed to parse/deserialize LockFile at {LockFilePath}. Nuking file from orbit", _lockFilePath); DebugHelper.WriteException(ex); try { @@ -260,7 +259,7 @@ private static bool IsProcessRunning(int pid) } catch (InvalidOperationException) { - // Process has exited (may occur if HasExited was not yet updated). + // The process has exited (may occur if HasExited was not yet updated). return false; } catch (Exception) @@ -274,7 +273,7 @@ private void WriteVersionInfoToLockFile(LockFileContent versionInfo) { if (_lockFileStream == null) { - DebugHelper.WriteLine($"VersionEnforcer.WriteVersionInfoToLockFile() called when _lockFileStream is null. Redefining."); + _logger.Information($"VersionEnforcer.WriteVersionInfoToLockFile() called when _lockFileStream is null. Redefining."); _lockFileStream = new FileStream( _lockFilePath, FileMode.OpenOrCreate, @@ -302,9 +301,10 @@ public void Dispose() { if (_lockFileStream == null) { - DebugHelper.WriteLine(_ownsLockFile - ? $"VersionEnforcer owns the lock file at {_lockFilePath} yet _lockFileStream is null! BUG!" - : $"VersionLock _lockFileStream is null! Lockfile at {_lockFilePath} "); + _logger.Information(_ownsLockFile + ? string.Format($"VersionEnforcer owns the lock file at {{0}} yet {nameof(_lockFileStream)} is null! BUG!", + _lockFilePath) + : string.Format($"VersionLock {nameof(_lockFileStream)} is null! Lockfile at {{0}} ", _lockFilePath)); } var lockfileInfo = ReadLockFileContent(); if (lockfileInfo is not null && !IsProcessRunning(lockfileInfo.ProcessId)) _ownsLockFile = true; @@ -317,13 +317,12 @@ public void Dispose() } catch (Exception ex) { - DebugHelper.WriteLine($"VersionLock failed to delete lockfile {_lockFilePath} while disposing."); - DebugHelper.WriteException(ex); + _logger.Error(ex, "VersionLock failed to delete lockfile {LockFilePath} while disposing", _lockFilePath); } } else { - DebugHelper.WriteLine($"VersionEnforcer does not own lockfile {_lockFilePath}. Leaving it be."); + _logger.Information("VersionEnforcer does not own lockfile {LockFilePath}. Leaving it be", _lockFilePath); } _lockFileStream?.Dispose(); _lockFileStream = null; diff --git a/SnapX.Core/Watch/WatchFolder.cs b/SnapX.Core/Watch/WatchFolder.cs index f26ce4493..7767f95b9 100644 --- a/SnapX.Core/Watch/WatchFolder.cs +++ b/SnapX.Core/Watch/WatchFolder.cs @@ -1,140 +1,264 @@ - // SPDX-License-Identifier: GPL-3.0-or-later using System.Diagnostics; +using Microsoft.Extensions.FileProviders; using SnapX.Core.Job; using SnapX.Core.Utils; namespace SnapX.Core.Watch; -public class WatchFolder : IDisposable +public sealed class WatchFolder : IDisposable { - public WatchFolderSettings Settings { get; set; } - public TaskSettings TaskSettings { get; set; } + public WatchFolderSettings? Settings { get; set; } + public TaskSettings? TaskSettings { get; set; } // Assuming this is for other task-related settings public delegate void FileWatcherTriggerEventHandler(string? path); + public event FileWatcherTriggerEventHandler? FileWatcherTrigger; - public event FileWatcherTriggerEventHandler FileWatcherTrigger; - - private SynchronizationContext context; - private FileSystemWatcher fileWatcher; - private List timers = []; + private SynchronizationContext _context; + private FileSystemWatcher? _fileSystemWatcher; + private List _timers = []; + private PhysicalFileProvider? _fileProvider; - public virtual void Enable() + /// + /// Enables the file watcher. + /// + public void Enable() { Dispose(); - string? folderPath = FileHelpers.ExpandFolderVariables(Settings.FolderPath); + if (Settings == null) + { + DebugHelper.WriteLine("WatchFolder settings are not configured."); + return; + } + + var folderPath = FileHelpers.ExpandFolderVariables(Settings.FolderPath); + + if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath)) + { + DebugHelper.WriteLine($"Invalid or non-existent folder path: {folderPath}"); + return; + } + + _context = SynchronizationContext.Current ?? new SynchronizationContext(); - if (!string.IsNullOrEmpty(folderPath) && Directory.Exists(folderPath)) + try { - context = SynchronizationContext.Current ?? new SynchronizationContext(); + _fileSystemWatcher = new FileSystemWatcher(folderPath); + if (!string.IsNullOrEmpty(Settings.Filter)) + { + _fileSystemWatcher.Filter = Settings.Filter; + } + _fileSystemWatcher.IncludeSubdirectories = Settings.IncludeSubdirectories; + + _fileSystemWatcher.Created += FileWatcher_Created; + _fileSystemWatcher.Changed += FileWatcher_Changed; + _fileSystemWatcher.Renamed += FileWatcher_Renamed; + _fileSystemWatcher.Deleted += FileWatcher_Deleted; - fileWatcher = new FileSystemWatcher(folderPath); - if (!string.IsNullOrEmpty(Settings.Filter)) fileWatcher.Filter = Settings.Filter; - fileWatcher.IncludeSubdirectories = Settings.IncludeSubdirectories; - fileWatcher.Created += fileWatcher_Created; - fileWatcher.EnableRaisingEvents = true; + _fileSystemWatcher.EnableRaisingEvents = true; + DebugHelper.WriteLine($"Started monitoring directory: {folderPath} with filter: {_fileSystemWatcher.Filter}"); + + // If you still want to initialize PhysicalFileProvider for other (non-event) purposes: + _fileProvider = new PhysicalFileProvider(folderPath) + { + UsePollingFileWatcher = true, + UseActivePolling = true + }; + // Note: _fileProvider won't directly trigger the FileWatcherTrigger event. + // You'd need to manually check for changes using IChangeToken if you wanted to use it for eventing. + } + catch (Exception ex) + { + DebugHelper.WriteException(ex, $"Error enabling file watcher for {folderPath}"); } } - protected void OnFileWatcherTrigger(string? path) + /// + /// Invokes the FileWatcherTrigger event on the synchronization context. + /// + /// The path of the file that triggered the event. + private void OnFileWatcherTrigger(string? path) { - FileWatcherTrigger?.Invoke(path); + _context.Post(state => FileWatcherTrigger?.Invoke((string?)state), path); } - private async void fileWatcher_Created(object sender, FileSystemEventArgs e) + /// + /// Handles the FileSystemWatcher.Created event. + /// + private async void FileWatcher_Created(object sender, FileSystemEventArgs e) { - CleanElapsedTimers(); + DebugHelper.WriteLine($"File created event: {e.FullPath}"); + await HandleFileEvent(e.FullPath); + } + + /// + /// Handles the FileSystemWatcher.Changed event. + /// + private async void FileWatcher_Changed(object sender, FileSystemEventArgs e) + { + DebugHelper.WriteLine($"File changed event: {e.FullPath}"); + await HandleFileEvent(e.FullPath); + } + + /// + /// Handles the FileSystemWatcher.Renamed event. + /// + private async void FileWatcher_Renamed(object sender, RenamedEventArgs e) + { + DebugHelper.WriteLine($"File renamed event: Old path: {e.OldFullPath}, New path: {e.FullPath}"); + // For renamed, we typically care about the new path + await HandleFileEvent(e.FullPath); + } - string? path = e.FullPath; + /// + /// Handles the FileSystemWatcher.Deleted event. + /// + private void FileWatcher_Deleted(object sender, FileSystemEventArgs e) + { + DebugHelper.WriteLine($"File deleted event: {e.FullPath}"); + // No need to wait for file unlock/size for deleted files, just log or trigger if needed. + // For deletion, you might have a separate event or just log. + // If you need to trigger something for deleted files, consider a separate event or flag in FileWatcherTrigger. + } + + + /// + /// Common handler for file system events, including debounce and file locking checks. + /// + /// The full path of the file. + private async Task HandleFileEvent(string path) + { + CleanElapsedTimers(); - foreach (WatchFolderDuplicateEventTimer timer in timers) + // Skip directories for file processing + if (Directory.Exists(path)) { - if (timer.IsDuplicateEvent(path)) - { - return; - } + DebugHelper.WriteLine($"Skipping directory event for: {path}"); + return; } - timers.Add(new WatchFolderDuplicateEventTimer(path)); + // Debounce duplicate events + if (_timers.Any(timer => timer.IsDuplicateEvent(path))) + { + DebugHelper.WriteLine($"Skipping duplicate event for: {path}"); + return; + } + _timers.Add(new WatchFolderDuplicateEventTimer(path)); - int successCount = 0; + var successCount = 0; long previousSize = -1; - await Helpers.WaitWhileAsync(() => - { - if (!FileHelpers.IsFileLocked(path)) + // Wait until the file is no longer locked and its size stabilizes + await Helpers.WaitWhileAsync( + check: () => { - long currentSize = FileHelpers.GetFileSize(path); - - if (currentSize > 0 && currentSize == previousSize) + if (!File.Exists(path)) { - successCount++; + DebugHelper.WriteLine($"File {path} no longer exists during processing."); + return false; } - previousSize = currentSize; - return successCount < 4; - } + if (!FileHelpers.IsFileLocked(path)) + { + var currentSize = FileHelpers.GetFileSize(path); - previousSize = -1; - return true; - }, 250, 5000, () => - { - context.Post(state => OnFileWatcherTrigger(path), null); - }, 1000); + if (currentSize > 0 && currentSize == previousSize) + { + successCount++; + } + else + { + successCount = 0; + } + + previousSize = currentSize; + return successCount < 4; // Wait for 4 consecutive stable size readings + } + + previousSize = -1; // Reset previous size if file is locked + return true; + }, + interval: 250, + timeout: 5000, + waitStart: 0, + onSuccess: () => + { + OnFileWatcherTrigger(path); + }); } - protected void CleanElapsedTimers() + /// + /// Cleans up elapsed duplicate event timers. + /// + private void CleanElapsedTimers() { - for (int i = 0; i < timers.Count; i++) - { - if (timers[i].IsElapsed) - { - timers.Remove(timers[i]); - } - } + _timers.RemoveAll(timer => timer.IsElapsed); } + /// + /// Disposes the FileSystemWatcher. + /// public void Dispose() { - if (fileWatcher != null) + if (_fileSystemWatcher != null) { - fileWatcher.Dispose(); + _fileSystemWatcher.EnableRaisingEvents = false; + _fileSystemWatcher.Created -= FileWatcher_Created; + _fileSystemWatcher.Changed -= FileWatcher_Changed; + _fileSystemWatcher.Renamed -= FileWatcher_Renamed; + _fileSystemWatcher.Deleted -= FileWatcher_Deleted; + _fileSystemWatcher.Dispose(); + _fileSystemWatcher = null; + DebugHelper.WriteLine("FileSystemWatcher disposed."); } + _fileProvider?.Dispose(); + _fileProvider = null; } } public class WatchFolderDuplicateEventTimer { - private const int expireTime = 1000; + private const int ExpireTimeMs = 1000; // Timer expires after 1 second - private Stopwatch timer; - private string? path; + private Stopwatch _timer; + private string? _path; + /// + /// Indicates if the timer has elapsed. + /// public bool IsElapsed { get { - return timer.ElapsedMilliseconds >= expireTime; + return _timer.ElapsedMilliseconds >= ExpireTimeMs; } } + /// + /// Initializes a new instance of the WatchFolderDuplicateEventTimer. + /// + /// The path of the file. public WatchFolderDuplicateEventTimer(string? path) { - timer = Stopwatch.StartNew(); - this.path = path; + _timer = Stopwatch.StartNew(); + _path = path; } + /// + /// Checks if the given path is a duplicate event and restarts the timer if it is. + /// + /// The path to check. + /// True if it's a duplicate event within the expiration time, otherwise false. public bool IsDuplicateEvent(string? path) { - bool result = path == this.path && !IsElapsed; + bool result = path == _path && !IsElapsed; if (result) { - timer = Stopwatch.StartNew(); + _timer.Restart(); // Restart the timer for the duplicate event } return result; } } - diff --git a/SnapX.Core/Watch/WatchFolderManager.cs b/SnapX.Core/Watch/WatchFolderManager.cs index d3942e982..f47923bc1 100644 --- a/SnapX.Core/Watch/WatchFolderManager.cs +++ b/SnapX.Core/Watch/WatchFolderManager.cs @@ -1,8 +1,6 @@ - // SPDX-License-Identifier: GPL-3.0-or-later -using SnapX.Core.Hotkey; using SnapX.Core.Job; using SnapX.Core.Upload; using SnapX.Core.Utils; @@ -11,7 +9,7 @@ namespace SnapX.Core.Watch; public class WatchFolderManager : IDisposable { - public List WatchFolders { get; private set; } + public List? WatchFolders { get; private set; } public void UpdateWatchFolders() { @@ -27,16 +25,16 @@ public void UpdateWatchFolders() AddWatchFolder(defaultWatchFolderSetting, SnapX.DefaultTaskSettings); } - foreach (HotkeySettings hotkeySetting in SnapX.HotkeysConfig.Hotkeys) + foreach (var hotkeySetting in SnapX.HotkeysConfig.Hotkeys) { - foreach (WatchFolderSettings watchFolderSetting in hotkeySetting.TaskSettings.WatchFolderList) + foreach (var watchFolderSetting in hotkeySetting.TaskSettings.WatchFolderList) { AddWatchFolder(watchFolderSetting, hotkeySetting.TaskSettings); } } } - private WatchFolder FindWatchFolder(WatchFolderSettings watchFolderSetting) + private WatchFolder? FindWatchFolder(WatchFolderSettings watchFolderSetting) { return WatchFolders.FirstOrDefault(watchFolder => watchFolder.Settings == watchFolderSetting); } @@ -46,7 +44,7 @@ private bool IsExist(WatchFolderSettings watchFolderSetting) return FindWatchFolder(watchFolderSetting) != null; } - public void AddWatchFolder(WatchFolderSettings watchFolderSetting, TaskSettings taskSettings) + public void AddWatchFolder(WatchFolderSettings watchFolderSetting, TaskSettings? taskSettings) { if (!IsExist(watchFolderSetting)) { @@ -55,19 +53,19 @@ public void AddWatchFolder(WatchFolderSettings watchFolderSetting, TaskSettings taskSettings.WatchFolderList.Add(watchFolderSetting); } - WatchFolder watchFolder = new WatchFolder(); + var watchFolder = new WatchFolder(); watchFolder.Settings = watchFolderSetting; watchFolder.TaskSettings = taskSettings; watchFolder.FileWatcherTrigger += origPath => { var taskSettingsCopy = TaskSettings.GetSafeTaskSettings(taskSettings); - string? destPath = origPath; + var destPath = origPath; if (watchFolderSetting.MoveFilesToScreenshotsFolder) { - string? screenshotsFolder = TaskHelpers.GetScreenshotsFolder(taskSettingsCopy); - string fileName = Path.GetFileName(origPath); + var screenshotsFolder = TaskHelpers.GetScreenshotsFolder(taskSettingsCopy); + var fileName = Path.GetFileName(origPath); destPath = Path.Combine(screenshotsFolder, fileName); FileHelpers.CreateDirectoryFromFilePath(destPath); File.Move(origPath, destPath); @@ -87,43 +85,32 @@ public void AddWatchFolder(WatchFolderSettings watchFolderSetting, TaskSettings public void RemoveWatchFolder(WatchFolderSettings watchFolderSetting) { - using (WatchFolder watchFolder = FindWatchFolder(watchFolderSetting)) - { - if (watchFolder != null) - { - watchFolder.TaskSettings.WatchFolderList.Remove(watchFolderSetting); - WatchFolders.Remove(watchFolder); - } - } + using var watchFolder = FindWatchFolder(watchFolderSetting); + if (watchFolder == null) return; + watchFolder.TaskSettings?.WatchFolderList.Remove(watchFolderSetting); + WatchFolders?.Remove(watchFolder); } public void UpdateWatchFolderState(WatchFolderSettings watchFolderSetting) { - WatchFolder watchFolder = FindWatchFolder(watchFolderSetting); - if (watchFolder != null) + var watchFolder = FindWatchFolder(watchFolderSetting); + if (watchFolder == null) return; + if (watchFolder.TaskSettings?.WatchFolderEnabled ?? false) { - if (watchFolder.TaskSettings.WatchFolderEnabled) - { - watchFolder.Enable(); - } - else - { - watchFolder.Dispose(); - } + watchFolder.Enable(); + } + else + { + watchFolder.Dispose(); } } public void UnregisterAllWatchFolders() { - if (WatchFolders != null) + if (WatchFolders == null) return; + foreach (var watchFolder in WatchFolders.OfType()) { - foreach (WatchFolder watchFolder in WatchFolders) - { - if (watchFolder != null) - { - watchFolder.Dispose(); - } - } + watchFolder.Dispose(); } } diff --git a/SnapX.Core/Watch/WatchFolderSettings.cs b/SnapX.Core/Watch/WatchFolderSettings.cs index ec1edf7c1..e26a06956 100644 --- a/SnapX.Core/Watch/WatchFolderSettings.cs +++ b/SnapX.Core/Watch/WatchFolderSettings.cs @@ -1,4 +1,3 @@ - // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/SnapX.Core/XML/org.freedesktop.DBus.xml b/SnapX.Core/XML/org.freedesktop.DBus.xml new file mode 100644 index 000000000..3f2b33864 --- /dev/null +++ b/SnapX.Core/XML/org.freedesktop.DBus.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SnapX.Core/XML/org.kde.KWin.ScreenShot2.xml b/SnapX.Core/XML/org.kde.KWin.ScreenShot2.xml new file mode 100644 index 000000000..bc4eb4039 --- /dev/null +++ b/SnapX.Core/XML/org.kde.KWin.ScreenShot2.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SnapX.Core/wayland.xml b/SnapX.Core/XML/wayland.xml similarity index 100% rename from SnapX.Core/wayland.xml rename to SnapX.Core/XML/wayland.xml diff --git a/SnapX.NativeMessagingHost/Program.cs b/SnapX.NativeMessagingHost/Program.cs index f4495d83f..dd3b84773 100644 --- a/SnapX.NativeMessagingHost/Program.cs +++ b/SnapX.NativeMessagingHost/Program.cs @@ -7,7 +7,7 @@ if (args.Length == 0) { - Console.WriteLine("This executable is used to receive data from a browser addon and send it to SnapX."); + Console.WriteLine(@"This executable is used to receive data from a browser addon and send it to SnapX."); return; } diff --git a/SnapX.NativeMessagingHost/SnapX.NativeMessagingHost.csproj b/SnapX.NativeMessagingHost/SnapX.NativeMessagingHost.csproj index 7a7743e09..401e124b4 100644 --- a/SnapX.NativeMessagingHost/SnapX.NativeMessagingHost.csproj +++ b/SnapX.NativeMessagingHost/SnapX.NativeMessagingHost.csproj @@ -2,6 +2,7 @@ Exe SnapX_NativeMessagingHost + SnapX.NativeMessagingHost.Tests SnapX NativeMessagingHost none false diff --git a/SnapX.sln b/SnapX.sln index a21af2f2d..9396cf703 100644 --- a/SnapX.sln +++ b/SnapX.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.32112.339 @@ -21,62 +21,105 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SnapX.NativeMessagingHost", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{96432C2D-0F1D-4B69-97CB-9F54C1873C1E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build.Tests", "tests\Build.Tests\Build.Tests.csproj", "{3783A9EF-B03E-48C3-9EF8-91A9E40372B4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C5AE4585-E9EC-4FA3-B75A-E1210635ACB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C5AE4585-E9EC-4FA3-B75A-E1210635ACB6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C5AE4585-E9EC-4FA3-B75A-E1210635ACB6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C5AE4585-E9EC-4FA3-B75A-E1210635ACB6}.Release|Any CPU.Build.0 = Release|Any CPU - {E7DE6237-AEA2-498B-8F56-9B392472C490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7DE6237-AEA2-498B-8F56-9B392472C490}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7DE6237-AEA2-498B-8F56-9B392472C490}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7DE6237-AEA2-498B-8F56-9B392472C490}.Release|Any CPU.Build.0 = Release|Any CPU - {DBDB0DAA-B3AE-4CC4-A8C2-20550B7F32E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DBDB0DAA-B3AE-4CC4-A8C2-20550B7F32E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBDB0DAA-B3AE-4CC4-A8C2-20550B7F32E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DBDB0DAA-B3AE-4CC4-A8C2-20550B7F32E3}.Release|Any CPU.Build.0 = Release|Any CPU - {E1C94415-3424-4517-A2A1-B2FDD1F59C67}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E1C94415-3424-4517-A2A1-B2FDD1F59C67}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1C94415-3424-4517-A2A1-B2FDD1F59C67}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E1C94415-3424-4517-A2A1-B2FDD1F59C67}.Release|Any CPU.Build.0 = Release|Any CPU - {750C6F46-2C5A-4488-81D3-3B35CA50F3EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {750C6F46-2C5A-4488-81D3-3B35CA50F3EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {750C6F46-2C5A-4488-81D3-3B35CA50F3EE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {750C6F46-2C5A-4488-81D3-3B35CA50F3EE}.Release|Any CPU.Build.0 = Release|Any CPU - {D13441B6-96E1-4D1B-8A95-58A7D6CB1E24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D13441B6-96E1-4D1B-8A95-58A7D6CB1E24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D13441B6-96E1-4D1B-8A95-58A7D6CB1E24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D13441B6-96E1-4D1B-8A95-58A7D6CB1E24}.Release|Any CPU.Build.0 = Release|Any CPU - {1A190E53-1419-4CC2-B0E5-3BC7EA861C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A190E53-1419-4CC2-B0E5-3BC7EA861C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A190E53-1419-4CC2-B0E5-3BC7EA861C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A190E53-1419-4CC2-B0E5-3BC7EA861C8B}.Release|Any CPU.Build.0 = Release|Any CPU - {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|Any CPU.Build.0 = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|x64.ActiveCfg = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|x64.Build.0 = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|x86.Build.0 = Debug|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|Any CPU.Build.0 = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|x64.ActiveCfg = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|x64.Build.0 = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|x86.ActiveCfg = Release|Any CPU + {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|x86.Build.0 = Release|Any CPU {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|x64.ActiveCfg = Debug|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|x64.Build.0 = Debug|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|x86.ActiveCfg = Debug|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Debug|x86.Build.0 = Debug|Any CPU {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|Any CPU.Build.0 = Release|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|x64.ActiveCfg = Release|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|x64.Build.0 = Release|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|x86.ActiveCfg = Release|Any CPU + {74428450-9146-4434-B34F-D9D3213D7B0E}.Release|x86.Build.0 = Release|Any CPU {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|x64.ActiveCfg = Debug|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|x64.Build.0 = Debug|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|x86.ActiveCfg = Debug|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Debug|x86.Build.0 = Debug|Any CPU {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|Any CPU.ActiveCfg = Release|Any CPU {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|Any CPU.Build.0 = Release|Any CPU - {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C0D2877-B8F3-4D84-BD4C-E89173EBDD96}.Release|Any CPU.Build.0 = Release|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|x64.ActiveCfg = Release|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|x64.Build.0 = Release|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|x86.ActiveCfg = Release|Any CPU + {89525D3B-F639-4C0B-8CFF-F55A0C52D344}.Release|x86.Build.0 = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|x64.ActiveCfg = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|x64.Build.0 = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|x86.ActiveCfg = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Debug|x86.Build.0 = Debug|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|Any CPU.Build.0 = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|x64.ActiveCfg = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|x64.Build.0 = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|x86.ActiveCfg = Release|Any CPU + {3AAB8CC5-156D-4738-93D3-625BAA9D2ABD}.Release|x86.Build.0 = Release|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Debug|x64.ActiveCfg = Debug|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Debug|x64.Build.0 = Debug|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Debug|x86.ActiveCfg = Debug|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Debug|x86.Build.0 = Debug|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Release|x64.ActiveCfg = Release|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Release|x64.Build.0 = Release|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Release|x86.ActiveCfg = Release|Any CPU + {254E398D-F7F5-4B2A-9024-5C121EA6C564}.Release|x86.Build.0 = Release|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|x64.ActiveCfg = Debug|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|x64.Build.0 = Debug|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|x86.ActiveCfg = Debug|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Debug|x86.Build.0 = Debug|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|x64.ActiveCfg = Release|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|x64.Build.0 = Release|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|x86.ActiveCfg = Release|Any CPU + {96432C2D-0F1D-4B69-97CB-9F54C1873C1E}.Release|x86.Build.0 = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|x64.ActiveCfg = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|x64.Build.0 = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|x86.ActiveCfg = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Debug|x86.Build.0 = Debug|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|Any CPU.Build.0 = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|x64.ActiveCfg = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|x64.Build.0 = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|x86.ActiveCfg = Release|Any CPU + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3783A9EF-B03E-48C3-9EF8-91A9E40372B4} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DEACF1C2-28EE-44DF-B55E-2234F6137272} EndGlobalSection diff --git a/SnapX.slnx b/SnapX.slnx index 364873989..7272b6be3 100644 --- a/SnapX.slnx +++ b/SnapX.slnx @@ -4,11 +4,12 @@ - + - + + \ No newline at end of file diff --git a/build/Build.cs b/build/Build.cs index 9b986b6d0..29cc2d14f 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -78,7 +78,7 @@ await FileSystem.FileWriteAllTextAsync(manifestFile, json.ToJsonString(new JsonS private Task HandleRustLibCopy(string rootDirectory, string outputDir) { const string rustLib = "libsnapxrust.dylib"; - var sourcePath = Path.Combine(rootDirectory, "SnapX.Core", "ScreenCapture", "Rust", "target", "release", rustLib); + var sourcePath = Path.Combine(rootDirectory, "SnapX.Core", "SharpCapture", "Rust", "target", "release", rustLib); if (!File.Exists(sourcePath)) return Task.CompletedTask; diff --git a/build/BuildConfig.cs b/build/BuildConfig.cs index cb0660494..06aab9622 100644 --- a/build/BuildConfig.cs +++ b/build/BuildConfig.cs @@ -34,7 +34,7 @@ public string Docdir public string Icondir => Path.Join(Datadir, "icons", "hicolor"); public string Runtime { get; set; } = RuntimeInformation.RuntimeIdentifier; public string Metainfodir => Path.Join(Datadir, "metainfo"); - public string RootDirectory { get; } = Path.GetRelativePath(Directory.GetCurrentDirectory(), DirectoryService.FindRoot()); + public string RootDirectory { get; set; } = Path.GetRelativePath(Directory.GetCurrentDirectory(), DirectoryService.FindRoot()); public string PackagingDirectory => Path.Combine(RootDirectory, "packaging"); public string Tarballdir => Path.Combine(PackagingDirectory, "tarball"); public string Appdir => Path.Combine(PackagingDirectory, "AppDir"); @@ -82,7 +82,11 @@ public bool ShouldSkip(string stepName) public string[] Targets { get; init; } = []; public string[] SkippedStepsRaw { get; init; } = []; - public string OutputDir { get; init; } = "Output"; + public string OutputDir + { + get => field ??= Path.Combine(RootDirectory, "Output"); + set; + } public string Configuration { get; init; } = "Release"; public bool EnableWrapperScriptFallback { get; init; } public bool DisableWrapperScript { get; set; } = OperatingSystem.IsWindows(); diff --git a/build/CLI.cs b/build/CLI.cs index d9b68c2a5..2faabb6d1 100644 --- a/build/CLI.cs +++ b/build/CLI.cs @@ -100,7 +100,6 @@ public async Task InvokeAsync(string[] args, Func handle { Description = "The directory to output builds artifacts to.", Arity = ArgumentArity.ExactlyOne, - DefaultValueFactory = _ => "Output" }; rootCommand.Options.Add(outputDirOption); @@ -169,7 +168,7 @@ public async Task InvokeAsync(string[] args, Func handle var config = new BuildConfig { Targets = parseResult.GetValue(targetsArgument) ?? [], - OutputDir = parseResult.GetValue(outputDirOption) ?? "Output", + OutputDir = parseResult.GetValue(outputDirOption)!, Configuration = parseResult.GetValue(configurationOption) ?? "Release", ExtraArgs = parseResult.GetValue(extraArgsOption) ?? "", SkippedStepsRaw = parseResult.GetValue(skipStepOption) ?? [], @@ -202,7 +201,6 @@ public async Task InvokeAsync(string[] args, Func handle if (prefix is not null) config.Prefix = prefix; if (libDir is not null) config.LibDir = libDir; if (docDir is not null) config.Docdir = docDir; - // Set skipped steps based on parsed options config.SetSkippedSteps(config.SkippedStepsRaw); diff --git a/build/CommandRunner.cs b/build/CommandRunner.cs index e9dca3e59..8730c8af4 100644 --- a/build/CommandRunner.cs +++ b/build/CommandRunner.cs @@ -16,7 +16,7 @@ public async Task InstallFile(string source, string destination, string permissi var directoryPath = Path.GetDirectoryName(destination); if (!string.IsNullOrEmpty(directoryPath) && !Directory.Exists(directoryPath) && !File.Exists(directoryPath)) { - DirectoryService.EnsureDirectoryExists(directoryPath); + new DirectoryService(Logger, this).EnsureDirectoryExists(directoryPath); } if (source.Contains("dSYM", StringComparison.InvariantCultureIgnoreCase)) { diff --git a/build/DirectoryService.cs b/build/DirectoryService.cs index 014fa7cc4..b0d954768 100644 --- a/build/DirectoryService.cs +++ b/build/DirectoryService.cs @@ -53,7 +53,7 @@ public static void TryDeleteMatchingFiles(string directoryPath, string[] searchP TryDeleteFile(file); } } - public static void EnsureDirectoryExists(string directory) + public void EnsureDirectoryExists(string directory) { if (Directory.Exists(directory)) return; try diff --git a/build/FS.cs b/build/FS.cs index c98b55545..1e3f8b7e0 100644 --- a/build/FS.cs +++ b/build/FS.cs @@ -1,6 +1,6 @@ namespace DefaultNamespace; -public class FS(IBuildLogger Logger, CommandRunner CommandRunner) : IFileSystem +public class FS(IBuildLogger Logger, ICommandRunner CommandRunner) : IFileSystem { public async Task TryDeleteFile(string path) { @@ -89,7 +89,7 @@ public async Task FileWriteAllTextAsync(string path, string contents) public Task EnsureDirectoryExistsAsync(string path) { - DirectoryService.EnsureDirectoryExists(path); + new DirectoryService(Logger, CommandRunner).EnsureDirectoryExists(path); return Task.CompletedTask; } } diff --git a/build/IFileSystem.cs b/build/IFileSystem.cs index 14650de91..e941a491f 100644 --- a/build/IFileSystem.cs +++ b/build/IFileSystem.cs @@ -4,6 +4,9 @@ public interface IFileSystem { void FileCopy(string sourceFileName, string destFileName, bool overwrite); void DirectoryDelete(string path, bool recursive); + Task TryDeleteMatchingFiles(string directory, string[] searchPatterns); + Task TryDeleteEmptyDir(string directory); + Task TryDeleteFile(string path); string[] DirectoryGetFiles(string path, string searchPattern, SearchOption searchOption); string[] DirectoryGetDirectories(string path, string searchPattern, SearchOption searchOption); Task FileReadAllTextAsync(string path); diff --git a/build/Install.cs b/build/Install.cs index 5f47f496c..65323d8b7 100644 --- a/build/Install.cs +++ b/build/Install.cs @@ -1,6 +1,6 @@ namespace DefaultNamespace; -public class Install(IBuildLogger Logger, ICommandRunner CommandRunner, FS FileSystem, BuildConfig config) +public class Install(IBuildLogger Logger, ICommandRunner CommandRunner, IFileSystem FileSystem, BuildConfig config) { public async Task ProcessInstall() { @@ -13,6 +13,7 @@ public async Task ProcessInstall() private void LogInstallationPaths() { Logger.Information($"--- Installation Paths ---"); + Logger.Information($"Build Output: {config.OutputDir}"); Logger.Information($"Root directory: {config.RootDirectory}"); Logger.Information($"Destination Directory (DESTDIR): {config.DestDir}"); Logger.Information($"Prefix: {config.Prefix}"); diff --git a/build/Program.cs b/build/Program.cs index 5b2ae808a..916de18d1 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -8,9 +8,8 @@ namespace DefaultNamespace; internal class Program { - private static readonly ConsoleLogger logger = new(); - private static readonly CommandRunner commandRunner = new(logger); - internal static readonly DirectoryService directoryService = new(logger, commandRunner); + private static readonly IBuildLogger logger = new ConsoleLogger(); + private static readonly ICommandRunner commandRunner = new CommandRunner(logger); private static readonly FS fileSystem = new(logger, commandRunner); private async Task ExecuteAsync(BuildConfig config) diff --git a/build/Tarball.cs b/build/Tarball.cs index d9fd7419c..b236caec2 100644 --- a/build/Tarball.cs +++ b/build/Tarball.cs @@ -1,6 +1,6 @@ namespace DefaultNamespace; -public class Tarball(IBuildLogger Logger, ICommandRunner CommandRunner, FS FileSystem, BuildConfig config) +public class Tarball(IBuildLogger Logger, ICommandRunner CommandRunner, IFileSystem FileSystem, BuildConfig config) { public async Task ProcessTarball() { diff --git a/build/Uninstall.cs b/build/Uninstall.cs index 6903773dd..3dacbe882 100644 --- a/build/Uninstall.cs +++ b/build/Uninstall.cs @@ -1,6 +1,6 @@ namespace DefaultNamespace; -public class Uninstall(IBuildLogger Logger, FS FileSystem, BuildConfig config) +public class Uninstall(IBuildLogger Logger, IFileSystem FileSystem, BuildConfig config) { private static readonly string[] libraryExtensions = ["*.so", "*.dylib", "*.dll"]; public async Task ProcessUninstall() diff --git a/build/build.csproj b/build/build.csproj index d700adb55..7cd3f33cd 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -5,6 +5,7 @@ Exe DefaultNamespace preview + Build.Tests diff --git a/tests/Build.Tests/Build.Tests.csproj b/tests/Build.Tests/Build.Tests.csproj new file mode 100644 index 000000000..6c4f38f52 --- /dev/null +++ b/tests/Build.Tests/Build.Tests.csproj @@ -0,0 +1,22 @@ + + + + enable + enable + Exe + true + true + + + + + + + + + + + + + + diff --git a/tests/Build.Tests/BuildTests.cs b/tests/Build.Tests/BuildTests.cs new file mode 100644 index 000000000..d8a30e2ce --- /dev/null +++ b/tests/Build.Tests/BuildTests.cs @@ -0,0 +1,65 @@ +namespace DefaultNamespace; + +public class BuildTests +{ + private static readonly IBuildLogger logger = new ConsoleLogger(); + private static readonly ICommandRunner commandRunner = new CommandRunner(logger); + private static readonly FS fileSystem = new(logger, commandRunner); + + [Test] + public async Task Builds() + { + var cli = new CLI(); + BuildConfig? config = null; + await cli.InvokeAsync([], buildconfig => + { + config = buildconfig; + return Task.CompletedTask; + }); + if (config is null) throw new NullReferenceException(nameof(config)); + var buildProcessor = new Build(logger, commandRunner, fileSystem, config); + + await buildProcessor.ProcessBuildProject(config.ProjectsToBuild[0]); + } + + [Test, DependsOn(nameof(Builds))] + public async Task Installs() + { + // var snapx = new SnapX.Core.SnapX(); + // #if RELEASE + // snapx.silenceLogging(); + // #elif DEBUG + // #else + // snapx.silenceLogging(); + // #endif + // snapx.start([]); + // + // var CLIManager = snapx.GetCLIManager(); + // + // Task.Run(() => CLIManager.UseCommandLineArgs().GetAwaiter().GetResult()).ConfigureAwait(false).GetAwaiter().GetResult(); + var cli = new CLI(); + BuildConfig? config = null; + await cli.InvokeAsync([], buildconfig => + { + config = buildconfig; + return Task.CompletedTask; + }); + if (config is null) throw new NullReferenceException(nameof(config)); + config.Prefix = Path.Join(Path.DirectorySeparatorChar.ToString(), "usr"); + config.DestDir = Path.Join(AppContext.BaseDirectory, nameof(BuildTests)); + + var installer = new Install(logger, commandRunner, fileSystem, config); + + await installer.ProcessInstall(); + } + [After(Test)] + public void Cleanup() + { + var testDir = Path.Join(AppContext.BaseDirectory, nameof(BuildTests)); + if (Directory.Exists(testDir)) + { + Directory.Delete(testDir, recursive: true); + } + } + +} diff --git a/tests/Build.Tests/GlobalHooks.cs b/tests/Build.Tests/GlobalHooks.cs new file mode 100644 index 000000000..6275eee25 --- /dev/null +++ b/tests/Build.Tests/GlobalHooks.cs @@ -0,0 +1,23 @@ +// You can use attributes at the assembly level to apply to all tests in the assembly +// Here you could define global logic that would affect all tests + +[assembly: Retry(3)] +[assembly: System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + +namespace DefaultNamespace; + + +public class GlobalHooks +{ + [Before(TestSession)] + public static void SetUp() + { + Console.WriteLine(@"Or you can define methods that do stuff before..."); + } + + [After(TestSession)] + public static void CleanUp() + { + Console.WriteLine(@"...and after!"); + } +}