mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 23:34:10 +02:00
feat: add image handling actions and improve IRC message formatting
This commit is contained in:
@@ -7,6 +7,16 @@ using Attribute = Terminal.Gui.Drawing.Attribute;
|
||||
|
||||
namespace EchoHub.Client.UI.Chat;
|
||||
|
||||
/// <summary>An action a click on an attachment line can trigger.</summary>
|
||||
public enum AttachmentAction
|
||||
{
|
||||
OpenImage,
|
||||
SaveImage,
|
||||
}
|
||||
|
||||
/// <summary>Inclusive column range on a chat line that triggers an attachment action when clicked.</summary>
|
||||
public readonly record struct AttachmentActionSpan(int StartCol, int EndCol, AttachmentAction Action);
|
||||
|
||||
/// <summary>
|
||||
/// A single line in the chat, composed of colored segments.
|
||||
/// </summary>
|
||||
@@ -20,6 +30,14 @@ public partial class ChatLine
|
||||
public string? AttachmentFileName { get; set; }
|
||||
public AttachmentKind? AttachmentKind { get; set; }
|
||||
public string? SenderUsername { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Clickable sub-line targets (e.g. the "[open]" and "[save original]" brackets under an
|
||||
/// image). Columns are relative to the unwrapped line, so only the first wrapped line
|
||||
/// keeps them. Null means the whole line uses the kind's default action.
|
||||
/// </summary>
|
||||
public List<AttachmentActionSpan>? ActionSpans { get; set; }
|
||||
|
||||
/// <summary>Number of spaces to prepend on continuation lines when this line is word-wrapped.</summary>
|
||||
public int ContinuationIndent { get; set; }
|
||||
|
||||
@@ -160,6 +178,10 @@ public partial class ChatLine
|
||||
wrapped.IsMention = IsMention;
|
||||
}
|
||||
|
||||
// Span columns only line up with the first wrapped line; later lines fall
|
||||
// back to the kind's default action.
|
||||
results[0].ActionSpans = ActionSpans;
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@@ -443,9 +443,7 @@ public sealed class ChatMessageManager
|
||||
lines.Add(new ChatLine(segments));
|
||||
}
|
||||
}
|
||||
lines.Add(AttachmentActionLine(
|
||||
$"[↓ save original] {attachment.FileName} [{FormatFileSize(attachment.FileSize)}]",
|
||||
ChatColors.FileAttr, attachment));
|
||||
lines.Add(ImageActionLine(attachment));
|
||||
break;
|
||||
|
||||
case Core.Models.AttachmentKind.Audio:
|
||||
@@ -489,6 +487,41 @@ public sealed class ChatMessageManager
|
||||
return lines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the action line below an image preview: "[open] [↓ save original] name [size]".
|
||||
/// Each bracket is an <see cref="AttachmentActionSpan"/> so a mouse click can target it;
|
||||
/// keyboard activation (Enter) uses the default action, open.
|
||||
/// </summary>
|
||||
private static ChatLine ImageActionLine(AttachmentDto attachment)
|
||||
{
|
||||
var segments = RailPrefix();
|
||||
var col = segments.Sum(s => s.Text.GetColumns());
|
||||
var spans = new List<AttachmentActionSpan>();
|
||||
|
||||
void AddAction(string text, AttachmentAction action)
|
||||
{
|
||||
var width = text.GetColumns();
|
||||
spans.Add(new AttachmentActionSpan(col, col + width - 1, action));
|
||||
segments.Add(new(text, ChatColors.FileAttr));
|
||||
col += width;
|
||||
}
|
||||
|
||||
AddAction("[open]", AttachmentAction.OpenImage);
|
||||
segments.Add(new(" ", null));
|
||||
col += 1;
|
||||
AddAction("[↓ save original]", AttachmentAction.SaveImage);
|
||||
segments.Add(new($" {attachment.FileName} [{FormatFileSize(attachment.FileSize)}]", ChatColors.FileAttr));
|
||||
|
||||
return new ChatLine(segments)
|
||||
{
|
||||
AttachmentUrl = attachment.Url,
|
||||
AttachmentFileName = attachment.FileName,
|
||||
AttachmentKind = attachment.Kind,
|
||||
ActionSpans = spans,
|
||||
ContinuationPrefixSegments = RailPrefix(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a clickable attachment line carrying the metadata the message list uses to
|
||||
/// route activation (play audio, download file, save original image).
|
||||
|
||||
Reference in New Issue
Block a user