fish-station/Content.Client/_Sunrise/UserInterface/CustomControls/EmojiPickerWindow.cs

398 lines
13 KiB
C#

using Content.Client._Sunrise.Messenger;
using Content.Shared._Sunrise.Messenger;
using Content.Shared._Sunrise.SunriseCCVars;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
using System.Numerics;
using Content.Client.Resources;
using Robust.Shared.Input;
namespace Content.Client._Sunrise.UserInterface.CustomControls;
public sealed class EmojiPickerWindow : DefaultWindow
{
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
private readonly BoxContainer? _emojiPickerContentContainer;
private readonly List<string> _recentEmojis = new();
private readonly HashSet<string> _favoriteEmojis = new();
public event Action<string>? OnEmojiSelected;
private ClientEmojiSystem EmojiSystem => _entitySystemManager.GetEntitySystem<ClientEmojiSystem>();
private SpriteSystem SpriteSystem => _entitySystemManager.GetEntitySystem<SpriteSystem>();
public EmojiPickerWindow()
{
IoCManager.InjectDependencies(this);
Title = Loc.GetString("messenger-emoji-picker-title");
MinSize = new Vector2(445, 400);
Resizable = false;
var container = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true,
VerticalExpand = true,
Margin = new Thickness(8)
};
var scrollContainer = new ScrollContainer
{
HorizontalExpand = true,
VerticalExpand = true,
HScrollEnabled = false,
ReserveScrollbarSpace = true
};
_emojiPickerContentContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true,
Margin = new Thickness(0, 0, 0, 5)
};
scrollContainer.AddChild(_emojiPickerContentContainer);
container.AddChild(scrollContainer);
Contents.AddChild(container);
LoadSavedEmojis();
UpdateEmojiPickerContent();
}
public void UpdateEmojiPickerContent()
{
if (_emojiPickerContentContainer == null)
return;
_emojiPickerContentContainer.RemoveAllChildren();
var allEmojis = EmojiSystem.GetAllEmojis().ToList();
var emojiDict = allEmojis.ToDictionary(e => e.Code, e => e);
BuildRecentEmojisSection(_emojiPickerContentContainer, emojiDict);
BuildFavoriteEmojisSection(_emojiPickerContentContainer, allEmojis);
BuildAllEmojisSection(_emojiPickerContentContainer, allEmojis);
}
private StyleBoxTexture CreateEmojiPanelStyle()
{
var panelTex = _resourceCache.GetTexture("/Textures/Interface/Nano/rounded_button_bordered.svg.96dpi.png");
var panelStyle = new StyleBoxTexture
{
Texture = panelTex
};
panelStyle.SetPatchMargin(StyleBox.Margin.All, 5);
panelStyle.SetContentMarginOverride(StyleBox.Margin.All, 8);
panelStyle.Modulate = Color.FromHex("#2F2F35");
return panelStyle;
}
private void BuildRecentEmojisSection(BoxContainer contentContainer, Dictionary<string, EmojiPrototype> emojiDict)
{
var recentPanel = new PanelContainer
{
HorizontalExpand = true,
Margin = new Thickness(0, 0, 0, 10),
PanelOverride = CreateEmojiPanelStyle()
};
var recentSection = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true
};
recentSection.AddChild(new Label
{
Text = Loc.GetString("messenger-emoji-recent-title"),
StyleClasses = { "Bold" },
Margin = new Thickness(0, 0, 0, 4)
});
if (_recentEmojis.Count > 0)
{
var recentContainer = new GridContainer
{
Columns = 5,
HorizontalExpand = true
};
var recentToShow = _recentEmojis.TakeLast(5).Reverse().ToList();
foreach (var emojiCode in recentToShow)
{
if (emojiDict.TryGetValue(emojiCode, out var emoji))
{
recentContainer.AddChild(CreateEmojiButton(emoji, false));
}
}
recentSection.AddChild(recentContainer);
}
else
{
recentSection.AddChild(new Label
{
Text = Loc.GetString("messenger-emoji-recent-empty-hint"),
StyleClasses = { "LabelSubText" }
});
}
recentPanel.AddChild(recentSection);
contentContainer.AddChild(recentPanel);
}
private void BuildFavoriteEmojisSection(BoxContainer contentContainer, List<EmojiPrototype> allEmojis)
{
var favoritePanel = new PanelContainer
{
HorizontalExpand = true,
Margin = new Thickness(0, 0, 0, 10),
PanelOverride = CreateEmojiPanelStyle()
};
var favoriteSection = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true
};
favoriteSection.AddChild(new Label
{
Text = Loc.GetString("messenger-emoji-favorite-title"),
StyleClasses = { "Bold" },
Margin = new Thickness(0, 0, 0, 4)
});
if (_favoriteEmojis.Count > 0)
{
var favoriteContainer = new GridContainer
{
Columns = 5,
HorizontalExpand = true
};
var favoriteEmojisList = allEmojis.Where(e => _favoriteEmojis.Contains(e.Code)).ToList();
foreach (var emoji in favoriteEmojisList)
{
favoriteContainer.AddChild(CreateEmojiButton(emoji, true));
}
favoriteSection.AddChild(favoriteContainer);
}
else
{
favoriteSection.AddChild(new Label
{
Text = Loc.GetString("messenger-emoji-favorite-hint"),
StyleClasses = { "LabelSubText" },
Margin = new Thickness(0, 4, 0, 0)
});
}
favoritePanel.AddChild(favoriteSection);
contentContainer.AddChild(favoritePanel);
}
private void BuildAllEmojisSection(BoxContainer contentContainer, List<EmojiPrototype> allEmojis)
{
var allPanel = new PanelContainer
{
HorizontalExpand = true,
PanelOverride = CreateEmojiPanelStyle()
};
var allSection = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true
};
allSection.AddChild(new Label
{
Text = Loc.GetString("messenger-emoji-all-title"),
StyleClasses = { "Bold" },
Margin = new Thickness(0, 0, 0, 4)
});
var allEmojisContainer = new GridContainer
{
Columns = 5,
HorizontalExpand = true
};
var nonFavoriteEmojis = allEmojis.Where(e => !_favoriteEmojis.Contains(e.Code)).ToList();
foreach (var emoji in nonFavoriteEmojis)
{
allEmojisContainer.AddChild(CreateEmojiButton(emoji, false));
}
allSection.AddChild(allEmojisContainer);
allPanel.AddChild(allSection);
contentContainer.AddChild(allPanel);
}
private Button CreateEmojiButton(EmojiPrototype emoji, bool isFavorite)
{
var emojiButton = new Button
{
MinSize = new Vector2(75, 75),
MaxSize = new Vector2(75, 75),
ToolTip = emoji.Code
};
try
{
var spriteSpec = new SpriteSpecifier.Rsi(new ResPath(emoji.SpritePath), emoji.SpriteState);
var state = SpriteSystem.RsiStateLike(spriteSpec);
emojiButton.Label.Visible = false;
if (state.IsAnimated)
{
var animatedRect = new AnimatedTextureRect
{
SetWidth = 65,
SetHeight = 65,
HorizontalAlignment = Control.HAlignment.Center,
VerticalAlignment = Control.VAlignment.Center
};
animatedRect.SetFromSpriteSpecifier(spriteSpec);
animatedRect.DisplayRect.HorizontalExpand = true;
animatedRect.DisplayRect.VerticalExpand = true;
animatedRect.DisplayRect.Stretch = TextureRect.StretchMode.KeepAspectCentered;
emojiButton.AddChild(animatedRect);
}
else
{
var texture = SpriteSystem.Frame0(spriteSpec);
var textureRect = new TextureRect
{
Texture = texture,
SetWidth = 45,
SetHeight = 45,
HorizontalAlignment = Control.HAlignment.Center,
VerticalAlignment = Control.VAlignment.Center,
Stretch = TextureRect.StretchMode.KeepAspectCentered
};
emojiButton.AddChild(textureRect);
}
}
catch
{
emojiButton.Text = emoji.Code;
}
var emojiCode = emoji.Code;
emojiButton.OnPressed += _ =>
{
OnEmojiSelected?.Invoke(emojiCode);
AddToRecentEmojis(emojiCode);
UpdateEmojiPickerContent();
};
emojiButton.OnKeyBindDown += args =>
{
if (args.Function == EngineKeyFunctions.UIRightClick)
{
args.Handle();
ToggleFavoriteEmoji(emojiCode);
UpdateEmojiPickerContent();
}
};
return emojiButton;
}
private void AddToRecentEmojis(string emojiCode)
{
_recentEmojis.Remove(emojiCode);
_recentEmojis.Add(emojiCode);
if (_recentEmojis.Count > 5)
{
_recentEmojis.RemoveAt(0);
}
SaveRecentEmojis();
}
private void ToggleFavoriteEmoji(string emojiCode)
{
if (!_favoriteEmojis.Add(emojiCode))
{
_favoriteEmojis.Remove(emojiCode);
}
SaveFavoriteEmojis();
}
private void LoadSavedEmojis()
{
HashSet<string>? allEmojis = null;
try
{
allEmojis = EmojiSystem.GetAllEmojis().Select(e => e.Code).ToHashSet();
}
catch { }
try
{
var recentEmojisStr = _configurationManager.GetCVar(SunriseCCVars.MessengerRecentEmojis);
if (!string.IsNullOrWhiteSpace(recentEmojisStr))
{
var emojiCodes = recentEmojisStr.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
_recentEmojis.Clear();
foreach (var code in emojiCodes)
{
if (string.IsNullOrWhiteSpace(code) || (allEmojis != null && !allEmojis.Contains(code)))
continue;
_recentEmojis.Add(code);
if (_recentEmojis.Count >= 5) break;
}
}
}
catch { _recentEmojis.Clear(); }
try
{
var favoriteEmojisStr = _configurationManager.GetCVar(SunriseCCVars.MessengerFavoriteEmojis);
if (!string.IsNullOrWhiteSpace(favoriteEmojisStr))
{
var emojiCodes = favoriteEmojisStr.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
_favoriteEmojis.Clear();
foreach (var code in emojiCodes)
{
if (string.IsNullOrWhiteSpace(code) || (allEmojis != null && !allEmojis.Contains(code)))
continue;
_favoriteEmojis.Add(code);
}
}
}
catch { _favoriteEmojis.Clear(); }
}
private void SaveRecentEmojis()
{
try
{
var emojiCodesStr = string.Join(",", _recentEmojis);
_configurationManager.SetCVar(SunriseCCVars.MessengerRecentEmojis, emojiCodesStr);
_configurationManager.SaveToFile();
}
catch { }
}
private void SaveFavoriteEmojis()
{
try
{
var emojiCodesStr = string.Join(",", _favoriteEmojis);
_configurationManager.SetCVar(SunriseCCVars.MessengerFavoriteEmojis, emojiCodesStr);
_configurationManager.SaveToFile();
}
catch { }
}
}