Revamp printer activation settings

This commit is contained in:
2026-05-31 22:20:22 +02:00
parent e3c153fb0f
commit cfe141efc9
8 changed files with 329 additions and 133 deletions
+14 -4
View File
@@ -12,7 +12,7 @@ Alle Endpunkte erfordern einen Bearer Token (JWT oder API-Key):
Authorization: Bearer {token}
```
`/printers/register`, `/jobs/next`, `/jobs/:id/image`, `/jobs/:id/printed` und `/jobs/:id/error` benötigen keine spezifische Permission, nur einen gültigen Token. `POST /jobs` und `POST /preview` erfordern `VIEW_SCANNER`.
`/printers/register`, `/printers/:printerId/deactivate`, `/jobs/next`, `/jobs/:id/image`, `/jobs/:id/printed` und `/jobs/:id/error` benötigen keine spezifische Permission, nur einen gültigen Token. `POST /jobs` und `POST /preview` erfordern `VIEW_SCANNER`.
## 1. Job manuell anlegen (Frontend -> Backend)
@@ -67,9 +67,9 @@ Content-Type: image/png
Body: binäres PNG-Bild.
## 3. Drucker registrieren (Benutzeraktion in den Agent-Einstellungen)
## 3. Drucker aktivieren/deaktivieren (Benutzeraktion in den Agent-Einstellungen)
Der Agent ruft diesen Endpunkt nicht automatisch beim Start auf. Der Benutzer registriert die freigegebenen lokalen Windows-Drucker bewusst über die Agent-Einstellungen.
Der Agent ruft diesen Endpunkt nicht automatisch beim Start auf. Der Benutzer aktiviert lokale Windows-Drucker bewusst über die Agent-Einstellungen.
```http
POST /api/label-print-agent/printers/register
@@ -84,7 +84,8 @@ Content-Type: application/json
"windowsPrinterName": "Zebra GK420d",
"dpi": 203,
"defaultWidthMm": 101,
"defaultHeightMm": 76
"defaultHeightMm": 76,
"active": true
}
```
@@ -98,6 +99,15 @@ Content-Type: application/json
{ "ok": true }
```
Zum Deaktivieren entfernt der Benutzer den Haken `Aktiv`; der Agent ruft standardmäßig folgenden Endpunkt auf:
```http
POST /api/label-print-agent/printers/{printerId}/deactivate
Content-Type: application/json
```
Der Request Body entspricht dem Aktivieren, aber mit `"active": false`.
## 4. Nächsten Druckjob abrufen (Agent-Polling)
```http
+7 -4
View File
@@ -108,6 +108,7 @@ Beispiel:
"agentId": "PC-BUERO",
"encryptedApiToken": "",
"registerPrinterPath": "/api/label-print-agent/printers/register",
"deactivatePrinterPath": "/api/label-print-agent/printers/{printerId}/deactivate",
"nextJobPath": "/api/label-print-agent/jobs/next",
"imagePath": "/api/label-print-agent/jobs/{jobId}/image",
"reportSuccessPath": "/api/label-print-agent/jobs/{jobId}/printed",
@@ -128,7 +129,8 @@ Beispiel:
"windowsPrinterName": "DYMO LabelWriter 450",
"dpi": 300,
"defaultWidthMm": 57,
"defaultHeightMm": 32
"defaultHeightMm": 32,
"isActive": true
},
{
"printerId": "PC-BUERO_ZEBRA_GK420D",
@@ -136,7 +138,8 @@ Beispiel:
"windowsPrinterName": "Zebra GK420d",
"dpi": 203,
"defaultWidthMm": 101,
"defaultHeightMm": 76
"defaultHeightMm": 76,
"isActive": false
}
],
"worker": {
@@ -148,7 +151,7 @@ Beispiel:
Der API-Token wird lokal mit Windows DPAPI verschlüsselt gespeichert.
Der Agent registriert Drucker nicht automatisch. Im Tab `Drucker` kann der Benutzer die freigegebenen Einträge aus `printers` bewusst mit `Im Backend registrieren` an das Backend melden. Das Feld `printer` bleibt als Kompatibilitätsfeld für ältere Einstellungen erhalten; neue Jobs werden anhand von `windowsPrinterName` aus der Backend-Antwort auf den passenden lokalen Windows-Drucker gedruckt.
Der Agent registriert Drucker nicht automatisch. Im Tab `Drucker` steht links die Druckerliste; rechts werden Aktiv-Status, Breite, Höhe und DPI pro Drucker gepflegt. Wird `Aktiv` gesetzt, registriert der Agent den Drucker im Backend. Wird der Haken entfernt, ruft der Agent den Deaktivierungs-Endpunkt auf. Das Feld `printer` bleibt als Kompatibilitätsfeld für ältere Einstellungen erhalten; neue Jobs werden anhand von `windowsPrinterName` aus der Backend-Antwort auf den passenden lokalen Windows-Drucker gedruckt.
## Dymo-Druck
@@ -166,7 +169,7 @@ Wichtig:
1. Anwendung starten.
2. Tray-Symbol öffnen.
3. Im Tab `Backend` BaseUrl, AgentId und optional API-Token eintragen.
4. Im Tab `Drucker` die freigegebenen Drucker konfigurieren und mit `Im Backend registrieren` ans Backend melden.
4. Im Tab `Drucker` links einen Drucker auswählen und rechts `Aktiv`, Breite, Höhe und DPI setzen.
5. Im Tab `Allgemein` Polling aktivieren und Intervall setzen.
6. Mit `Jetzt prüfen` kann sofort ein Poll-Lauf ausgelöst werden; dabei werden alle aktuell verfügbaren Jobs verarbeitet.
+260 -98
View File
@@ -17,7 +17,14 @@ internal sealed class SettingsForm : Form
private readonly BackendClient _backendClient;
private readonly BackendPollingWorker _backendWorker;
private readonly UpdateService _updateService;
private readonly Dictionary<string, PrinterConfig> _printerConfigs = new(StringComparer.OrdinalIgnoreCase);
private UpdateCheckResult? _lastUpdateCheck;
private bool _loadingPrinters;
private bool _loadingPrinterConfig;
private string? _selectedSharedPrinterName;
private decimal _defaultLabelWidthMm = 57;
private decimal _defaultLabelHeightMm = 32;
private int _defaultPrinterDpi = 203;
private readonly CheckBox _autoStartCheckBox = new() { Text = "Autostart aktivieren", AutoSize = true };
private readonly CheckBox _workerEnabled = new() { Text = "Backend automatisch abfragen", AutoSize = true };
@@ -27,6 +34,8 @@ internal sealed class SettingsForm : Form
private readonly TextBox _backendBaseUrl = new() { Width = 420 };
private readonly TextBox _agentId = new() { Width = 260 };
private readonly TextBox _apiToken = new() { Width = 420, UseSystemPasswordChar = true };
private readonly TextBox _registerPrinterPath = new() { Width = 420 };
private readonly TextBox _deactivatePrinterPath = new() { Width = 420 };
private readonly TextBox _nextJobPath = new() { Width = 420 };
private readonly TextBox _imagePath = new() { Width = 420 };
private readonly TextBox _reportSuccessPath = new() { Width = 420 };
@@ -41,10 +50,12 @@ internal sealed class SettingsForm : Form
private readonly TextBox _updateAsset = new() { Width = 540, ReadOnly = true };
private readonly Button _installUpdateButton;
private readonly ComboBox _printer = new() { Width = 360, DropDownStyle = ComboBoxStyle.DropDownList };
private readonly CheckedListBox _sharedPrinters = new() { Width = 360, Height = 125, CheckOnClick = true };
private readonly ListBox _printerList = new() { Width = 320, Height = 285 };
private readonly CheckBox _printerActive = new() { Text = "Aktiv", AutoSize = true };
private readonly TextBox _windowsPrinterName = new() { Width = 360, ReadOnly = true };
private readonly NumericUpDown _labelWidth = new() { Minimum = 1, Maximum = 500, DecimalPlaces = 1, Value = 57, Width = 100 };
private readonly NumericUpDown _labelHeight = new() { Minimum = 1, Maximum = 500, DecimalPlaces = 1, Value = 32, Width = 100 };
private readonly NumericUpDown _printerDpi = new() { Minimum = 50, Maximum = 2400, Value = 203, Width = 100 };
private readonly TextBox _status = new()
{
@@ -81,6 +92,11 @@ internal sealed class SettingsForm : Form
tabs.TabPages.Add(CreateUpdatesTab());
tabs.TabPages.Add(CreateStatusTab());
Controls.Add(tabs);
_printerList.SelectedIndexChanged += (_, _) => SelectPrinter(GetPrinterName(_printerList.SelectedItem));
_printerActive.CheckedChanged += async (_, _) => await SetSelectedPrinterActiveFromUiAsync();
_labelWidth.ValueChanged += (_, _) => SaveSelectedPrinterConfig();
_labelHeight.ValueChanged += (_, _) => SaveSelectedPrinterConfig();
_printerDpi.ValueChanged += (_, _) => SaveSelectedPrinterConfig();
Load += (_, _) =>
{
@@ -106,33 +122,41 @@ internal sealed class SettingsForm : Form
panel.Controls.Add(Row(20, Label("BaseUrl", 160), _backendBaseUrl));
panel.Controls.Add(Row(60, Label("AgentId", 160), _agentId));
panel.Controls.Add(Row(100, Label("API Token", 160), _apiToken));
panel.Controls.Add(Row(140, Label("NextJobPath", 160), _nextJobPath));
panel.Controls.Add(Row(180, Label("ImagePath", 160), _imagePath));
panel.Controls.Add(Row(220, Label("ReportSuccessPath", 160), _reportSuccessPath));
panel.Controls.Add(Row(260, Label("ReportErrorPath", 160), _reportErrorPath));
panel.Controls.Add(Row(300, Label("SSE", 160), _useServerSentEvents));
panel.Controls.Add(Row(340, Label("EventsPath", 160), _eventsPath));
panel.Controls.Add(ButtonAt("Speichern", 180, 395, (_, _) => SaveBackend(showMessage: true)));
panel.Controls.Add(ButtonAt("Jetzt prüfen", 300, 395, async (_, _) => await PollOnceFromUiAsync()));
panel.Controls.Add(Row(140, Label("RegisterPrinterPath", 160), _registerPrinterPath));
panel.Controls.Add(Row(180, Label("DeactivatePrinterPath", 160), _deactivatePrinterPath));
panel.Controls.Add(Row(220, Label("NextJobPath", 160), _nextJobPath));
panel.Controls.Add(Row(260, Label("ImagePath", 160), _imagePath));
panel.Controls.Add(Row(300, Label("ReportSuccessPath", 160), _reportSuccessPath));
panel.Controls.Add(Row(340, Label("ReportErrorPath", 160), _reportErrorPath));
panel.Controls.Add(Row(380, Label("SSE", 160), _useServerSentEvents));
panel.Controls.Add(Row(420, Label("EventsPath", 160), _eventsPath));
panel.Controls.Add(ButtonAt("Speichern", 180, 475, (_, _) => SaveBackend(showMessage: true)));
panel.Controls.Add(ButtonAt("Jetzt prüfen", 300, 475, async (_, _) => await PollOnceFromUiAsync()));
return new TabPage("Backend") { Controls = { panel } };
}
private TabPage CreatePrinterTab()
{
var panel = CreatePaddedPanel();
panel.Controls.Add(Row(20, Label("Standarddrucker", 120), _printer));
var sharedLabel = Label("Freigegeben", 120);
sharedLabel.Left = 20;
sharedLabel.Top = 60;
_sharedPrinters.Left = 145;
_sharedPrinters.Top = 60;
panel.Controls.Add(sharedLabel);
panel.Controls.Add(_sharedPrinters);
panel.Controls.Add(Row(200, Label("Breite", 120), _labelWidth, Label("mm", 40)));
panel.Controls.Add(Row(240, Label("Höhe", 120), _labelHeight, Label("mm", 40)));
panel.Controls.Add(ButtonAt("Drucker neu laden", 140, 295, (_, _) => LoadPrinters()));
panel.Controls.Add(ButtonAt("Speichern", 300, 295, (_, _) => SavePrinter(showMessage: true)));
panel.Controls.Add(ButtonAt("Im Backend registrieren", 430, 295, async (_, _) => await RegisterPrintersFromUiAsync()));
var listLabel = Label("Drucker", 120);
listLabel.Left = 20;
listLabel.Top = 20;
_printerList.Left = 20;
_printerList.Top = 55;
panel.Controls.Add(listLabel);
panel.Controls.Add(_printerList);
var detailLeft = 380;
_printerActive.Left = detailLeft;
_printerActive.Top = 55;
panel.Controls.Add(_printerActive);
panel.Controls.Add(RowAt(detailLeft, 95, Label("Windows-Name", 120), _windowsPrinterName));
panel.Controls.Add(RowAt(detailLeft, 135, Label("Breite", 120), _labelWidth, Label("mm", 40)));
panel.Controls.Add(RowAt(detailLeft, 175, Label("Höhe", 120), _labelHeight, Label("mm", 40)));
panel.Controls.Add(RowAt(detailLeft, 215, Label("DPI", 120), _printerDpi));
panel.Controls.Add(ButtonAt("Drucker neu laden", 20, 365, (_, _) => LoadPrinters()));
panel.Controls.Add(ButtonAt("Speichern", detailLeft, 365, (_, _) => SavePrinter(showMessage: true)));
return new TabPage("Drucker") { Controls = { panel } };
}
@@ -168,6 +192,8 @@ internal sealed class SettingsForm : Form
_backendBaseUrl.Text = settings.Backend.BaseUrl;
_agentId.Text = settings.Backend.AgentId;
_apiToken.Text = _settingsStore.DecryptBackendApiToken(settings);
_registerPrinterPath.Text = settings.Backend.RegisterPrinterPath;
_deactivatePrinterPath.Text = settings.Backend.DeactivatePrinterPath;
_nextJobPath.Text = settings.Backend.NextJobPath;
_imagePath.Text = settings.Backend.ImagePath;
_reportSuccessPath.Text = settings.Backend.ReportSuccessPath;
@@ -183,34 +209,54 @@ internal sealed class SettingsForm : Form
_installUpdateButton.Enabled = false;
_lastUpdateCheck = null;
var primaryPrinter = GetPrimaryPrinter(settings);
_labelWidth.Value = primaryPrinter?.DefaultWidthMm ?? settings.Printer.LabelWidthMm;
_labelHeight.Value = primaryPrinter?.DefaultHeightMm ?? settings.Printer.LabelHeightMm;
_defaultLabelWidthMm = settings.Printer.LabelWidthMm;
_defaultLabelHeightMm = settings.Printer.LabelHeightMm;
_defaultPrinterDpi = settings.Printer.Dpi > 0 ? settings.Printer.Dpi : 203;
SetPrinterEditorEnabled(false);
}
private void LoadPrinters()
{
var settings = _settingsStore.Load();
var selected = GetPrimaryPrinter(settings)?.WindowsPrinterName ?? settings.Printer.PrinterName;
_printer.Items.Clear();
_sharedPrinters.Items.Clear();
var sharedPrinterNames = settings.Printers
.Select(printer => printer.WindowsPrinterName)
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToHashSet(StringComparer.OrdinalIgnoreCase);
_loadingPrinters = true;
_selectedSharedPrinterName = null;
_printerConfigs.Clear();
foreach (var printer in settings.Printers.Where(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName)))
{
_printerConfigs[printer.WindowsPrinterName] = ClonePrinterConfig(printer);
}
_printerList.Items.Clear();
var printers = _printerService.GetInstalledPrinters();
foreach (var printer in printers)
{
_printer.Items.Add(printer);
_sharedPrinters.Items.Add(printer, sharedPrinterNames.Contains(printer.Name));
EnsurePrinterConfig(printer.Name);
_printerList.Items.Add(printer);
}
var configuredPrinter = printers.FirstOrDefault(printer => string.Equals(printer.Name, selected, StringComparison.OrdinalIgnoreCase));
_printer.SelectedItem = configuredPrinter ?? printers.FirstOrDefault(printer => printer.IsDefault);
if (_printer.SelectedItem is null && _printer.Items.Count > 0)
foreach (var printerName in _printerConfigs.Keys
.Where(name => printers.All(printer => !string.Equals(printer.Name, name, StringComparison.OrdinalIgnoreCase)))
.OrderBy(name => name))
{
_printer.SelectedIndex = 0;
_printerList.Items.Add(printerName);
}
_loadingPrinters = false;
var selectedIndex = FindPrinterIndex(selected);
if (selectedIndex < 0 && _printerList.Items.Count > 0)
{
selectedIndex = 0;
}
if (selectedIndex >= 0)
{
_printerList.SelectedIndex = selectedIndex;
SelectPrinter(GetPrinterName(_printerList.SelectedItem));
return;
}
SetPrinterEditorEnabled(false);
}
private void SaveGeneral()
@@ -231,6 +277,8 @@ internal sealed class SettingsForm : Form
var normalizedToken = SettingsStore.NormalizeBackendApiToken(_apiToken.Text);
settings.Backend.EncryptedApiToken = _settingsStore.EncryptPassword(normalizedToken);
_apiToken.Text = normalizedToken;
settings.Backend.RegisterPrinterPath = _registerPrinterPath.Text.Trim();
settings.Backend.DeactivatePrinterPath = _deactivatePrinterPath.Text.Trim();
settings.Backend.NextJobPath = _nextJobPath.Text.Trim();
settings.Backend.ImagePath = _imagePath.Text.Trim();
settings.Backend.ReportSuccessPath = _reportSuccessPath.Text.Trim();
@@ -249,17 +297,19 @@ internal sealed class SettingsForm : Form
{
var settings = _settingsStore.Load();
var selectedPrinterName = GetSelectedPrinterName() ?? string.Empty;
var sharedPrinterNames = GetSharedPrinterNames();
SaveSelectedPrinterConfig();
settings.Printer.PrinterName = selectedPrinterName;
settings.Printer.LabelWidthMm = _labelWidth.Value;
settings.Printer.LabelHeightMm = _labelHeight.Value;
settings.Printers = sharedPrinterNames
.Select(printerName => BuildPrinterConfig(settings, printerName))
settings.Printer.Dpi = (int)_printerDpi.Value;
settings.Printers = _printerConfigs.Keys
.OrderBy(printerName => printerName)
.Select(printerName => BuildPrinterConfig(settings, printerName, fallbackToEditor: false))
.ToList();
if (settings.Printers.Count == 0 && !string.IsNullOrWhiteSpace(selectedPrinterName))
{
settings.Printers.Add(BuildPrinterConfig(settings, selectedPrinterName));
settings.Printers.Add(BuildPrinterConfig(settings, selectedPrinterName, fallbackToEditor: true));
}
_settingsStore.Save(settings);
@@ -301,34 +351,6 @@ internal sealed class SettingsForm : Form
}
}
private async Task RegisterPrintersFromUiAsync()
{
try
{
SaveBackend(showMessage: false);
SavePrinter(showMessage: false);
var settings = _settingsStore.Load();
var printerCount = settings.Printers.Count(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName));
if (printerCount == 0)
{
MessageBox.Show("Bitte zuerst mindestens einen Drucker konfigurieren.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
AppendStatus($"{printerCount} Drucker werden im Backend registriert...");
await _backendClient.RegisterPrintersAsync();
AppendStatus($"{printerCount} Drucker im Backend registriert.");
MessageBox.Show("Drucker wurden im Backend registriert.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
Log.Error(ex, "Printer registration failed");
AppendStatus($"Druckerregistrierung fehlgeschlagen: {ex.Message}");
MessageBox.Show($"Druckerregistrierung fehlgeschlagen: {ex.Message}", Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private async Task CheckForUpdateFromUiAsync()
{
try
@@ -408,34 +430,114 @@ internal sealed class SettingsForm : Form
private string? GetSelectedPrinterName()
{
return _printer.SelectedItem switch
return GetPrinterName(_printerList.SelectedItem);
}
private void SelectPrinter(string? printerName)
{
if (_loadingPrinters)
{
PrinterInfo printerInfo => printerInfo.Name,
string printerName => printerName,
_ => null
return;
}
if (string.Equals(_selectedSharedPrinterName, printerName, StringComparison.OrdinalIgnoreCase))
{
return;
}
SaveSelectedPrinterConfig();
if (string.IsNullOrWhiteSpace(printerName) || !_printerConfigs.TryGetValue(printerName, out var config))
{
_selectedSharedPrinterName = null;
SetPrinterEditorEnabled(false);
return;
}
_selectedSharedPrinterName = printerName;
SetPrinterEditorEnabled(true);
_loadingPrinterConfig = true;
try
{
_windowsPrinterName.Text = config.WindowsPrinterName;
_printerActive.Checked = config.IsActive;
_labelWidth.Value = Math.Clamp(config.DefaultWidthMm, (int)_labelWidth.Minimum, (int)_labelWidth.Maximum);
_labelHeight.Value = Math.Clamp(config.DefaultHeightMm, (int)_labelHeight.Minimum, (int)_labelHeight.Maximum);
_printerDpi.Value = Math.Clamp(config.Dpi, (int)_printerDpi.Minimum, (int)_printerDpi.Maximum);
}
finally
{
_loadingPrinterConfig = false;
}
}
private void SaveSelectedPrinterConfig()
{
if (_loadingPrinters || _loadingPrinterConfig || string.IsNullOrWhiteSpace(_selectedSharedPrinterName))
{
return;
}
var config = EnsurePrinterConfig(_selectedSharedPrinterName);
config.DefaultWidthMm = Math.Max(1, (int)Math.Round(_labelWidth.Value));
config.DefaultHeightMm = Math.Max(1, (int)Math.Round(_labelHeight.Value));
config.Dpi = (int)_printerDpi.Value;
config.IsActive = _printerActive.Checked;
}
private async Task SetSelectedPrinterActiveFromUiAsync()
{
if (_loadingPrinters || _loadingPrinterConfig || string.IsNullOrWhiteSpace(_selectedSharedPrinterName))
{
return;
}
try
{
SaveBackend(showMessage: false);
SaveSelectedPrinterConfig();
var config = BuildPrinterConfig(_settingsStore.Load(), _selectedSharedPrinterName, fallbackToEditor: false);
config.IsActive = _printerActive.Checked;
SavePrinter(showMessage: false);
await _backendClient.SetPrinterActiveAsync(config, config.IsActive);
AppendStatus($"Drucker {config.WindowsPrinterName} {(config.IsActive ? "aktiviert" : "deaktiviert")}.");
}
catch (Exception ex)
{
Log.Error(ex, "Could not update printer active state");
AppendStatus($"Aktiv-Status konnte nicht synchronisiert werden: {ex.Message}");
MessageBox.Show($"Aktiv-Status konnte nicht synchronisiert werden: {ex.Message}", Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private PrinterConfig EnsurePrinterConfig(string printerName)
{
if (_printerConfigs.TryGetValue(printerName, out var config))
{
return config;
}
config = new PrinterConfig
{
PrinterId = SettingsStore.BuildPrinterId(_agentId.Text.Trim(), printerName),
Name = printerName,
WindowsPrinterName = printerName,
Dpi = _defaultPrinterDpi,
DefaultWidthMm = Math.Max(1, (int)Math.Round(_defaultLabelWidthMm)),
DefaultHeightMm = Math.Max(1, (int)Math.Round(_defaultLabelHeightMm)),
IsActive = false
};
_printerConfigs[printerName] = config;
return config;
}
private List<string> GetSharedPrinterNames()
private PrinterConfig BuildPrinterConfig(AppSettings settings, string printerName, bool fallbackToEditor)
{
return _sharedPrinters.CheckedItems
.Cast<object>()
.Select(item => item switch
{
PrinterInfo printerInfo => printerInfo.Name,
string printerName => printerName,
_ => null
})
.Where(printerName => !string.IsNullOrWhiteSpace(printerName))
.Cast<string>()
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
private PrinterConfig BuildPrinterConfig(AppSettings settings, string printerName)
{
var existingPrinter = settings.Printers.FirstOrDefault(
printer => string.Equals(printer.WindowsPrinterName, printerName, StringComparison.OrdinalIgnoreCase));
var existingPrinter = _printerConfigs.TryGetValue(printerName, out var config)
? config
: settings.Printers.FirstOrDefault(printer => string.Equals(printer.WindowsPrinterName, printerName, StringComparison.OrdinalIgnoreCase));
var width = fallbackToEditor ? (int)Math.Round(_labelWidth.Value) : existingPrinter?.DefaultWidthMm ?? (int)Math.Round(settings.Printer.LabelWidthMm);
var height = fallbackToEditor ? (int)Math.Round(_labelHeight.Value) : existingPrinter?.DefaultHeightMm ?? (int)Math.Round(settings.Printer.LabelHeightMm);
var dpi = fallbackToEditor ? (int)_printerDpi.Value : existingPrinter?.Dpi ?? settings.Printer.Dpi;
return new PrinterConfig
{
PrinterId = string.IsNullOrWhiteSpace(existingPrinter?.PrinterId)
@@ -443,15 +545,70 @@ internal sealed class SettingsForm : Form
: existingPrinter.PrinterId,
Name = string.IsNullOrWhiteSpace(existingPrinter?.Name) ? printerName : existingPrinter.Name,
WindowsPrinterName = printerName,
Dpi = existingPrinter?.Dpi > 0 ? existingPrinter.Dpi : settings.Printer.Dpi,
DefaultWidthMm = Math.Max(1, (int)Math.Round(_labelWidth.Value)),
DefaultHeightMm = Math.Max(1, (int)Math.Round(_labelHeight.Value))
Dpi = Math.Max(1, dpi),
DefaultWidthMm = Math.Max(1, width),
DefaultHeightMm = Math.Max(1, height),
IsActive = existingPrinter?.IsActive ?? false
};
}
private static PrinterConfig? GetPrimaryPrinter(AppSettings settings)
{
return settings.Printers.FirstOrDefault(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName));
return settings.Printers.FirstOrDefault(printer => printer.IsActive && !string.IsNullOrWhiteSpace(printer.WindowsPrinterName))
?? settings.Printers.FirstOrDefault(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName));
}
private int FindPrinterIndex(string printerName)
{
for (var index = 0; index < _printerList.Items.Count; index++)
{
if (string.Equals(GetPrinterName(_printerList.Items[index]), printerName, StringComparison.OrdinalIgnoreCase))
{
return index;
}
}
return -1;
}
private static string? GetPrinterName(object? item)
{
return item switch
{
PrinterInfo printerInfo => printerInfo.Name,
string printerName => printerName,
_ => null
};
}
private static PrinterConfig ClonePrinterConfig(PrinterConfig printer)
{
return new PrinterConfig
{
PrinterId = printer.PrinterId,
Name = printer.Name,
WindowsPrinterName = printer.WindowsPrinterName,
Dpi = printer.Dpi,
DefaultWidthMm = printer.DefaultWidthMm,
DefaultHeightMm = printer.DefaultHeightMm,
IsActive = printer.IsActive
};
}
private void SetPrinterEditorEnabled(bool enabled)
{
_labelWidth.Enabled = enabled;
_labelHeight.Enabled = enabled;
_printerDpi.Enabled = enabled;
_printerActive.Enabled = enabled;
_windowsPrinterName.Enabled = enabled;
if (!enabled)
{
_loadingPrinterConfig = true;
_windowsPrinterName.Text = string.Empty;
_printerActive.Checked = false;
_loadingPrinterConfig = false;
}
}
private void AppendStatus(string message)
@@ -483,10 +640,15 @@ internal sealed class SettingsForm : Form
private static Label Label(string text, int width) => new() { Text = text, Width = width, TextAlign = ContentAlignment.MiddleLeft };
private static FlowLayoutPanel Row(int top, params Control[] controls)
{
return RowAt(20, top, controls);
}
private static FlowLayoutPanel RowAt(int left, int top, params Control[] controls)
{
var row = new FlowLayoutPanel
{
Left = 20,
Left = left,
Top = top,
Width = 760,
Height = 32,
@@ -116,7 +116,7 @@ internal sealed class TrayApplicationContext : ApplicationContext
}
var configuredPrinters = settings.Printers
.Where(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName))
.Where(printer => printer.IsActive && !string.IsNullOrWhiteSpace(printer.WindowsPrinterName))
.ToList();
if (configuredPrinters.Count == 0)
{
+42 -24
View File
@@ -38,34 +38,18 @@ public sealed class BackendClient
public async Task RegisterPrintersAsync(CancellationToken cancellationToken = default)
{
var settings = _settingsStore.Load();
foreach (var printer in settings.Printers.Where(IsRegisterablePrinter))
foreach (var printer in settings.Printers.Where(printer => printer.IsActive).Where(IsRegisterablePrinter))
{
var body = new
{
printerId = printer.PrinterId,
agentId = settings.Backend.AgentId,
name = printer.Name,
windowsPrinterName = printer.WindowsPrinterName,
dpi = printer.Dpi,
defaultWidthMm = printer.DefaultWidthMm,
defaultHeightMm = printer.DefaultHeightMm
};
using var request = CreateRequest(
HttpMethod.Post,
MakeAbsoluteUrl(settings.Backend.BaseUrl, settings.Backend.RegisterPrinterPath),
settings);
request.Content = JsonContent.Create(body);
using var response = await _httpClient.SendAsync(request, cancellationToken);
await EnsureSuccessWithDiagnosticsAsync(response, request, cancellationToken);
Log.Information(
"Registered printer {PrinterId} ({WindowsPrinterName}) for agent {AgentId}",
printer.PrinterId,
printer.WindowsPrinterName,
settings.Backend.AgentId);
await SetPrinterActiveAsync(settings, printer, active: true, cancellationToken);
}
}
public async Task SetPrinterActiveAsync(PrinterConfig printer, bool active, CancellationToken cancellationToken = default)
{
var settings = _settingsStore.Load();
await SetPrinterActiveAsync(settings, printer, active, cancellationToken);
}
public async Task<Bitmap> GetLabelImageAsync(BackendLabelJob job, CancellationToken cancellationToken = default)
{
if (!string.IsNullOrWhiteSpace(job.LabelImageBase64))
@@ -120,6 +104,40 @@ public sealed class BackendClient
await EnsureSuccessWithDiagnosticsAsync(response, request, cancellationToken);
}
private async Task SetPrinterActiveAsync(AppSettings settings, PrinterConfig printer, bool active, CancellationToken cancellationToken)
{
if (!IsRegisterablePrinter(printer))
{
throw new InvalidOperationException("Drucker kann ohne PrinterId und WindowsPrinterName nicht synchronisiert werden.");
}
var body = new
{
printerId = printer.PrinterId,
agentId = settings.Backend.AgentId,
name = printer.Name,
windowsPrinterName = printer.WindowsPrinterName,
dpi = printer.Dpi,
defaultWidthMm = printer.DefaultWidthMm,
defaultHeightMm = printer.DefaultHeightMm,
active
};
var path = active
? settings.Backend.RegisterPrinterPath
: settings.Backend.DeactivatePrinterPath.Replace("{printerId}", Uri.EscapeDataString(printer.PrinterId), StringComparison.OrdinalIgnoreCase);
using var request = CreateRequest(HttpMethod.Post, MakeAbsoluteUrl(settings.Backend.BaseUrl, path), settings);
request.Content = JsonContent.Create(body);
using var response = await _httpClient.SendAsync(request, cancellationToken);
await EnsureSuccessWithDiagnosticsAsync(response, request, cancellationToken);
Log.Information(
"{Action} printer {PrinterId} ({WindowsPrinterName}) for agent {AgentId}",
active ? "Activated" : "Deactivated",
printer.PrinterId,
printer.WindowsPrinterName,
settings.Backend.AgentId);
}
public async Task WatchServerSentEventsAsync(Func<CancellationToken, Task> onLabelJobAvailable, CancellationToken cancellationToken = default)
{
var settings = _settingsStore.Load();
@@ -55,7 +55,7 @@ public sealed class BackendPollingWorker : IDisposable
}
var configuredPrinters = settings.Printers
.Where(printer => !string.IsNullOrWhiteSpace(printer.WindowsPrinterName))
.Where(printer => printer.IsActive && !string.IsNullOrWhiteSpace(printer.WindowsPrinterName))
.ToList();
if (configuredPrinters.Count == 0)
{
@@ -22,6 +22,7 @@ public sealed class BackendSettings
public string AgentId { get; set; } = Environment.MachineName;
public string EncryptedApiToken { get; set; } = string.Empty;
public string RegisterPrinterPath { get; set; } = "/api/label-print-agent/printers/register";
public string DeactivatePrinterPath { get; set; } = "/api/label-print-agent/printers/{printerId}/deactivate";
public string NextJobPath { get; set; } = "/api/label-print-agent/jobs/next";
public string ImagePath { get; set; } = "/api/label-print-agent/jobs/{jobId}/image";
public string ReportSuccessPath { get; set; } = "/api/label-print-agent/jobs/{jobId}/printed";
@@ -53,6 +54,7 @@ public sealed class PrinterConfig
public int Dpi { get; set; } = 203;
public int DefaultWidthMm { get; set; } = 57;
public int DefaultHeightMm { get; set; } = 32;
public bool IsActive { get; set; } = true;
}
public sealed class WorkerSettings
@@ -101,7 +101,8 @@ public sealed class SettingsStore
WindowsPrinterName = settings.Printer.PrinterName,
Dpi = settings.Printer.Dpi,
DefaultWidthMm = Math.Max(1, (int)Math.Round(settings.Printer.LabelWidthMm)),
DefaultHeightMm = Math.Max(1, (int)Math.Round(settings.Printer.LabelHeightMm))
DefaultHeightMm = Math.Max(1, (int)Math.Round(settings.Printer.LabelHeightMm)),
IsActive = true
});
}