UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag. Oberflaeche - Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml (eigene ControlThemes statt Fluent umzufaerben). - Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite statt eigenem Fenster, Texteditor-Fenster. - ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt. Rocket.Chat - Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird nur, wenn wirklich etwas anliegt. - send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist. - Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei Annahmen waren falsch und sind korrigiert. Deploymentcenter - DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json) erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke. - AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Färbt den Hintergrund einer Chat-Sprechblase für Benutzer-Nachrichten.
|
||||
/// </summary>
|
||||
public sealed class ChatBubbleBrushConverter : IValueConverter
|
||||
{
|
||||
public static readonly ChatBubbleBrushConverter Instance = new();
|
||||
|
||||
private static readonly IBrush UserBubble = new SolidColorBrush(Color.FromArgb(0x28, 0x00, 0x78, 0xD4));
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool isUser && isUser)
|
||||
return UserBubble;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Richtet Chat-Sprechblasen aus: Rechts für den Benutzer, links für den Agenten.
|
||||
/// </summary>
|
||||
public sealed class ChatAlignmentConverter : IValueConverter
|
||||
{
|
||||
public static readonly ChatAlignmentConverter Instance = new();
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool isUser && isUser)
|
||||
return HorizontalAlignment.Right;
|
||||
|
||||
return HorizontalAlignment.Left;
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prüft, ob ein Tool-Name mit dem ConverterParameter übereinstimmt.
|
||||
/// </summary>
|
||||
public sealed class ToolMatchConverter : IValueConverter
|
||||
{
|
||||
public static readonly ToolMatchConverter Instance = new();
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string toolName && parameter is string targetTool)
|
||||
return toolName.Equals(targetTool, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Globalization;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Schlägt eine Symbol-Geometrie aus <c>Styles/Icons.axaml</c> über ihren Namen nach.
|
||||
///
|
||||
/// <para>Damit halten die Ansichtsmodelle nur den Namen („IconChat") statt einer
|
||||
/// <see cref="Geometry"/> — sie brauchen dann keinen Verweis auf <c>Avalonia.Media</c>,
|
||||
/// und die Navigationsleiste kommt mit einer schlichten Zeichenkette je Eintrag aus.</para>
|
||||
///
|
||||
/// <para>Dass hier keine Themenumschaltung nötig ist, ist kein Zufall: Die Geometrien sind
|
||||
/// themenunabhängig, gefärbt wird erst beim Zeichnen über die geerbte Vordergrundfarbe
|
||||
/// (siehe <c>Controls/StrokeIcon.cs</c>). Für Farben wäre dieser Weg falsch — ein einmal
|
||||
/// aufgelöster Pinsel bliebe beim Wechsel auf Dunkel stehen.</para>
|
||||
/// </summary>
|
||||
public sealed class IconConverter : IValueConverter
|
||||
{
|
||||
public static readonly IconConverter Instance = new();
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not string key || string.IsNullOrEmpty(key)) return null;
|
||||
if (Application.Current is not { } app) return null;
|
||||
|
||||
return app.TryFindResource(key, out var resource) ? resource as Geometry : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Der Pfeil am Einklapp-Schalter der Seitenleiste: zeigt nach links, solange
|
||||
/// eingeklappt werden kann, und nach rechts, wenn wieder aufgeklappt wird.
|
||||
/// </summary>
|
||||
public sealed class SidebarChevronConverter : IValueConverter
|
||||
{
|
||||
public static readonly SidebarChevronConverter Instance = new();
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
var isCollapsed = value is true;
|
||||
return IconConverter.Instance.Convert(
|
||||
isCollapsed ? "IconChevronRight" : "IconChevronLeft", targetType, parameter, culture);
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Layout;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Richtet Sprechblasen aus: rechts fuer den Benutzer, links fuer den Agenten.
|
||||
///
|
||||
/// <para>Ausrichtung und nicht Farbe — deshalb ist ein Konverter hier richtig. Der
|
||||
/// frueher danebenstehende ChatBubbleBrushConverter lieferte einen Pinsel mit festem
|
||||
/// Farbwert und ueberlebte den Themenwechsel nicht; die Hinterlegung eigener Nachrichten
|
||||
/// laeuft jetzt ueber die Stilklasse <c>card accent</c>.</para>
|
||||
/// </summary>
|
||||
public sealed class ChatAlignmentConverter : IValueConverter
|
||||
{
|
||||
public static readonly ChatAlignmentConverter Instance = new();
|
||||
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> value is true ? HorizontalAlignment.Right : HorizontalAlignment.Left;
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prueft, ob ein Werkzeugname mit dem <c>ConverterParameter</c> uebereinstimmt.
|
||||
/// Blendet im Werkzeug-Einstellungsbereich die passende Feldgruppe ein.
|
||||
/// </summary>
|
||||
public sealed class ToolMatchConverter : IValueConverter
|
||||
{
|
||||
public static readonly ToolMatchConverter Instance = new();
|
||||
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> value is string toolName && parameter is string targetTool
|
||||
&& toolName.Equals(targetTool, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Färbt eine Logzeile nach ihrer Stufe.
|
||||
///
|
||||
/// Bewusst nur Warnung und Fehler hervorgehoben — alles einzufärben macht die Ansicht
|
||||
/// unruhig und lenkt von genau den Zeilen ab, die auffallen sollen. Der Rest behält die
|
||||
/// Vordergrundfarbe des Themas und funktioniert damit hell wie dunkel.
|
||||
/// </summary>
|
||||
public sealed class LogLevelBrushConverter : IValueConverter
|
||||
{
|
||||
public static readonly LogLevelBrushConverter Instance = new();
|
||||
|
||||
private static readonly IBrush Error = new SolidColorBrush(Color.FromRgb(0xE8, 0x4B, 0x4B));
|
||||
private static readonly IBrush Warn = new SolidColorBrush(Color.FromRgb(0xD8, 0x9C, 0x2A));
|
||||
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> value as string switch
|
||||
{
|
||||
"ERR" or "FTL" => Error,
|
||||
"WRN" => Warn,
|
||||
// null heißt: Bindung greift nicht, das Steuerelement behält seine eigene
|
||||
// Farbe aus dem Thema.
|
||||
_ => null
|
||||
};
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
|
||||
namespace ClawdDotNet.Desktop.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Vergleicht eine Zeichenkette mit dem <c>ConverterParameter</c>, ohne Gross- und
|
||||
/// Kleinschreibung zu unterscheiden.
|
||||
///
|
||||
/// <para>Gedacht fuer <c>Classes.xyz="{Binding …}"</c>: Die Ansicht setzt damit eine
|
||||
/// Stilklasse, und die Farbe dazu steht in <c>Styles/Shell.axaml</c> an
|
||||
/// <c>DynamicResource</c>. Das ersetzt den frueheren LogLevelBrushConverter, der
|
||||
/// Pinsel mit festen Farbwerten zurueckgab — die blieben beim Wechsel auf Dunkel
|
||||
/// unveraendert stehen, weil ein einmal gelieferter Pinsel nichts mehr vom Thema
|
||||
/// mitbekommt.</para>
|
||||
/// </summary>
|
||||
public sealed class StringEqualsConverter : IValueConverter
|
||||
{
|
||||
public static readonly StringEqualsConverter Instance = new();
|
||||
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> value is string text && parameter is string expected
|
||||
&& text.Equals(expected, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
=> throw new NotSupportedException("Nur zur Anzeige.");
|
||||
}
|
||||
Reference in New Issue
Block a user