Examples/TwitchChatExample/TwitchChatExample.razor
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace TwitchAPI.Examples

<root>
</root>

@code
{
	/// <summary>
	/// The username of the Twitch Chat to connect to.
	/// </summary>
	[Property] string Username { get; set; }

	/// <summary>
	/// Whether or not to include the user's avatar images in the chat.
	/// </summary>
	[Property] bool HasAvatarImages { get; set; } = false;

	/// <summary>
	/// How long a message should be displayed for (in seconds).
	/// </summary>
	[Property, Group("Timing")] float MessageTime { get; set; } = 30f;

	/// <summary>
	/// How long a message should take to fade out (in seconds).
	/// </summary>
	[Property, Group("Timing")] float FadeTime { get; set; } = 0.5f;

	/// <summary>
	/// The position of the chat on the screen.
	/// </summary>
	[Property, Group("Styling")] Vector2 ChatPosition { get; set; } = new(5f, 95f);

	/// <summary>
	/// The size of the chat. Set to (0, 0) to scale automatically.
	/// </summary>
	[Property, Group("Styling")] Vector2 ChatSize { get; set; } = new(400f, 600f);

	/// <summary>
	/// The background color of the chat.
	/// </summary>
	[Property, Group("Styling")] Color BackgroundColor { get; set; } = Color.Transparent;

	/// <summary>
	/// The color of the text in the chat.
	/// </summary>
	[Property, Group("Styling")] Color TextColor { get; set; } = Color.White;

	/// <summary>
	/// The size of the text in the chat.
	/// </summary>
	[Property, Group("Styling")] float TextSize { get; set; } = 16f;

	/// <summary>
	/// The font family to use for the text in the chat.
	/// </summary>
	[Property, Group("Styling")] string FontFamily { get; set; } = "Poppins";

	/// <summary>
	/// The size of the gaps between messages in the chat.
	/// </summary>
	[Property, Group("Styling")] float GapSize { get; set; } = 8f;

	/// <summary>
	/// The padding around messages in the chat.
	/// </summary>
	[Property, Group("Styling")] float Padding { get; set; } = 8f;

	/// <summary>
	/// Whether or not to reverse the order of messages in the chat.
	/// </summary>
	[Property, Group("Styling")] bool ReverseOrder { get; set; } = false;

	/// <summary>
	/// Whether or not to use custom images for subscriber badges.
	/// </summary>
	[Property, Group("Badges")] bool HasCustomSubscriberBadges { get; set; } = false;

	/// <summary>
	/// The custom subscriber badges to use.
	/// </summary>
	[Property, Group("Badges"), InlineEditor, ShowIf(nameof(TwitchChatExample.HasCustomSubscriberBadges), true)] CustomSubscriberBadges SubscriberBadges { get; set; } = new();

	TwitchChatConnection Twitch;

	protected override void OnEnabled()
	{
		if (string.IsNullOrWhiteSpace(Username)) return;
		Twitch = new TwitchChatConnection(Username);
		Twitch.OnMessageReceived += OnMessageReceived;
		Twitch.OnMessageRemoved += OnMessageRemoved;
		Twitch.OnChatCleared += OnChatCleared;
	}

	protected override void OnDisabled()
	{
		if (Twitch is not null)
		{
			Twitch.OnMessageReceived -= OnMessageReceived;
			Twitch.OnMessageRemoved -= OnMessageRemoved;
			Twitch.OnChatCleared -= OnChatCleared;
			Twitch.Dispose();
		}
	}

	protected override void OnUpdate()
	{
		Panel.Style.BackgroundColor = BackgroundColor;
		Panel.Style.FontColor = TextColor;
		Panel.Style.FontSize = TextSize;
		Panel.Style.FontFamily = FontFamily;
		Panel.Style.RowGap = GapSize;
		Panel.Style.Padding = Padding;
		Panel.Style.FlexDirection = ReverseOrder ? FlexDirection.ColumnReverse : FlexDirection.Column;
		Panel.Style.JustifyContent = Justify.FlexEnd;

		if (ChatSize == 0)
		{
			Panel.Style.Width = Length.Auto;
			Panel.Style.Height = Length.Auto;
		}
		else
		{
			Panel.Style.Width = Length.Pixels(ChatSize.x);
			Panel.Style.Height = Length.Pixels(ChatSize.y);
		}

		Panel.Style.MaxWidth = Panel.Style.Width;
		Panel.Style.MaxHeight = Panel.Style.Height;

		if (ChatPosition.x < 50f)
		{
			Panel.Style.Left = Length.Percent(ChatPosition.x);
			Panel.Style.Right = default;
		}
		else
		{
			Panel.Style.Left = default;
			Panel.Style.Right = Length.Percent((100f - ChatPosition.x));
		}

		if (ChatPosition.y < 50f)
		{
			Panel.Style.Top = Length.Percent(ChatPosition.y);
			Panel.Style.Bottom = default;
		}
		else
		{
			Panel.Style.Top = default;
			Panel.Style.Bottom = Length.Percent((100f - ChatPosition.y));
		}
	}

	void OnMessageReceived(TwitchChatMessage message)
	{
		var entry = Panel.AddChild<TwitchChatEntry>();
		entry.ChatMessage = message;
		entry.Lifetime = MessageTime;
		entry.HasAvatarImages = HasAvatarImages;
	}

	void OnMessageRemoved(TwitchChatMessage message)
	{
		foreach (var child in Panel.Children)
		{
			if (child is TwitchChatEntry entry && entry.ChatMessage == message)
			{
				entry.Delete();
				break;
			}
		}
	}

	void OnChatCleared()
	{
		Panel.DeleteChildren();
	}

	protected override int BuildHash() => System.HashCode.Combine(Username);
}