fish-station/Content.Client/_Sunrise/CartridgeLoader/Cartridges/MessagePanel.xaml.cs
2026-01-30 06:28:52 +01:00

252 lines
8.1 KiB
C#

using System.Numerics;
using Content.Client._Sunrise.Messenger;
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Shared._Sunrise.Messenger;
using Content.Shared.StatusIcon;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.RichText;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client._Sunrise.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class MessagePanel : PanelContainer
{
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly NetTexturesManager _netTexturesManager = default!;
private ClientEmojiSystem? EmojiSystem => _entitySystemManager.GetEntitySystemOrNull<ClientEmojiSystem>();
private SpriteSystem GetSpriteSystem() => _entitySystemManager.GetEntitySystem<SpriteSystem>();
/// <summary>
/// ID сообщения для идентификации при обновлении
/// </summary>
public long MessageId { get; private set; }
private static readonly Type[] MessageTagsAllowed =
[
typeof(BoldItalicTag),
typeof(BoldTag),
typeof(BulletTag),
typeof(ColorTag),
typeof(HeadingTag),
typeof(ItalicTag),
typeof(EmojiTag),
];
public MessagePanel()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
_netTexturesManager.ResourceLoaded += OnResourceLoaded;
ImageButton.OnPressed += _ => ShowFullImage();
ImageBorder.PanelOverride = new StyleBoxFlat
{
BackgroundColor = Color.Transparent,
BorderColor = Color.Transparent,
BorderThickness = new Thickness(2)
};
ImageButton.OnMouseEntered += _ =>
{
if (ImageBorder.PanelOverride is StyleBoxFlat style)
{
style.BorderColor = Color.White.WithAlpha(0.6f);
}
};
ImageButton.OnMouseExited += _ =>
{
if (ImageBorder.PanelOverride is StyleBoxFlat style)
{
style.BorderColor = Color.Transparent;
}
};
}
public event Action<long>? OnDeleteMessage;
private Button? _deleteButton;
private string? _currentImagePath;
public void UpdateMessage(MessengerMessage message, bool isOwnMessage, bool isPersonalChat, string? currentUserId)
{
MessageId = message.MessageId;
SenderLabel.Text = message.SenderName;
TimeLabel.Text = message.Timestamp.ToString(@"hh\:mm");
UpdateJobIcon(message.SenderJobIconId);
var parsedContent = EmojiSystem?.ParseEmojis(message.Content) ?? message.Content;
ContentLabel.SetMessage(FormattedMessage.FromMarkupPermissive(parsedContent), MessageTagsAllowed);
ContentLabel.Visible = !string.IsNullOrWhiteSpace(message.Content);
if (isOwnMessage && _deleteButton == null)
{
_deleteButton = new Button
{
Text = "✖",
SetWidth = 24,
SetHeight = 24,
ToolTip = Loc.GetString("messenger-delete-message"),
Margin = new Thickness(2, 0)
};
_deleteButton.AddStyleClass(StyleClass.ButtonSmall);
_deleteButton.OnPressed += _ => OnDeleteMessage?.Invoke(MessageId);
RightContainer.AddChild(_deleteButton);
}
else if (!isOwnMessage && _deleteButton != null)
{
RightContainer.RemoveChild(_deleteButton);
_deleteButton = null;
}
var roundedButtonTex = _resourceCache.GetTexture("/Textures/Interface/Nano/rounded_button_bordered.svg.96dpi.png");
var roundedStyleBox = new StyleBoxTexture
{
Texture = roundedButtonTex
};
roundedStyleBox.SetPatchMargin(StyleBox.Margin.All, 5);
roundedStyleBox.SetPadding(StyleBox.Margin.All, 2);
roundedStyleBox.SetContentMarginOverride(StyleBox.Margin.Left, 8);
roundedStyleBox.SetContentMarginOverride(StyleBox.Margin.Right, 8);
roundedStyleBox.SetContentMarginOverride(StyleBox.Margin.Top, 6);
roundedStyleBox.SetContentMarginOverride(StyleBox.Margin.Bottom, 6);
if (isOwnMessage)
{
roundedStyleBox.Modulate = Color.FromHex("#2A4A5A");
}
else
{
roundedStyleBox.Modulate = Color.FromHex("#1E1E22");
}
MessagePanelContainer.PanelOverride = roundedStyleBox;
if (isPersonalChat && isOwnMessage && message.RecipientId != null)
{
ReadStatusIcon.Visible = true;
var readStatusTexturePath = message.IsRead
? new ResPath("/Textures/Interface/Actions/eyeopen.png")
: new ResPath("/Textures/Interface/Actions/eyeclose.png");
ReadStatusIcon.Texture = _resourceCache.GetTexture(readStatusTexturePath);
}
else
{
ReadStatusIcon.Visible = false;
}
UpdateImagePreview(message.ImagePath);
}
private void UpdateImagePreview(string? imagePath)
{
if (string.IsNullOrWhiteSpace(imagePath))
{
ImageButton.Visible = false;
_currentImagePath = null;
return;
}
_currentImagePath = imagePath;
var isAvailable = _netTexturesManager.EnsureResource(imagePath);
if (isAvailable)
{
LoadImageTexture(imagePath);
}
else
{
ImageButton.Visible = false;
}
}
private void ShowFullImage()
{
if (ImagePreview.Texture == null)
return;
var window = new DefaultWindow
{
Title = Loc.GetString("messenger-image-preview-title"),
MinSize = new Vector2(600, 600)
};
var textureRect = new TextureRect
{
Texture = ImagePreview.Texture,
Stretch = TextureRect.StretchMode.KeepAspect,
HorizontalExpand = true,
VerticalExpand = true
};
window.Contents.AddChild(textureRect);
window.OpenCentered();
}
private void OnResourceLoaded(string resourcePath)
{
if (_currentImagePath == resourcePath)
{
LoadImageTexture(resourcePath);
}
}
private void LoadImageTexture(string imagePath)
{
try
{
var uploadedPath = _netTexturesManager.GetUploadedPath(imagePath);
if (_resourceCache.TryGetResource<TextureResource>(uploadedPath, out var textureResource))
{
ImagePreview.Texture = textureResource.Texture;
ImageButton.Visible = true;
}
else
{
ImageButton.Visible = false;
}
}
catch
{
ImageButton.Visible = false;
}
}
/// <summary>
/// Обновляет иконку работы в панели сообщения
/// </summary>
private void UpdateJobIcon(ProtoId<JobIconPrototype>? jobIconId)
{
if (jobIconId != null && _prototypeManager.TryIndex(jobIconId.Value, out JobIconPrototype? jobIcon))
{
JobIconRect.Texture = GetSpriteSystem().Frame0(jobIcon.Icon);
JobIconRect.Visible = true;
}
else
{
var unknownIconId = new ProtoId<JobIconPrototype>("JobIconUnknown");
if (_prototypeManager.TryIndex(unknownIconId, out JobIconPrototype? unknownIcon))
{
JobIconRect.Texture = GetSpriteSystem().Frame0(unknownIcon.Icon);
JobIconRect.Visible = true;
}
else
{
JobIconRect.Visible = false;
}
}
}
}