2024-04-03 22:57:32 -04:00

553 lines
21 KiB
C#

using System.Reflection;
using GraphicsManager;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using Luski.GUI.MainScreen.UI.LuskiControls;
using Luski.net.Structures.Public;
using Luski.Shared.PublicServers.V1.Enums;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.GraphicsLibraryFramework;
namespace Luski.GUI.MainScreen.UI.PublicServers;
public class PublicChat : UserControl
{
public FlowLayout MessageFlow;
private Label title, desc;
private TextBox tb;
private SocketChannel? Channel;
UserControl titlecon;
private Rectangle? UserCon;
private SocketMessage? first;
private FlowLayout? memberflow = null;
public PublicChat()
{
base.Size = new(980.ScaleInt(), 866.ScaleInt());
base.BackgroundColor = new(40,40,40,255);
Anchor = ObjectAnchor.All;
Controls.Add(MessageFlow = new()
{
Size = new(base.Size.X, 761.ScaleInt()),
Location = new(0, 52.ScaleInt(), 0),
BackgroundColor = new(40,40,40,255),
Anchor = ObjectAnchor.All,
HScrollPixels = Globals.Settings.PerScrollPixels,
});
MessageFlow.FlowUpdate += MessageFlowOnFlowUpdate;
if (LuskiExperiments.GUI.MessageLiveSize.IsEnabled()) MessageFlow.SizeChanged += OnSizeChanged;
LuskiExperiments.GUI.MessageLiveSize.EventToggled += MessageLiveSizeOnEventToggled;
Task MessageLiveSizeOnEventToggled(bool arg)
{
if (arg) MessageFlow.SizeChanged += OnSizeChanged;
else MessageFlow.SizeChanged -= OnSizeChanged;
return Task.CompletedTask;
}
Controls.Add(titlecon = new UserControl()
{
Anchor = ObjectAnchor.Left | ObjectAnchor.Top | ObjectAnchor.Right,
Size = new(980.ScaleInt(), 48.ScaleInt()),
BackgroundColor = new(50,50,50,255),
});
if (LuskiExperiments.GUI.MemberList.IsEnabled())
{
UserCon =
new(Globals.ms.TextureManager.GetTextureResource("person.png"))
{
Size = new(24.ScaleInt()),
Location = new(944.ScaleInt(), 12.ScaleInt(),0),
Anchor = ObjectAnchor.Right | ObjectAnchor.Top,
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.LightGray
};
UserCon.MouseEnter += o => { UserCon.BackgroundColor = Color4.White; return Task.CompletedTask; };
UserCon.MouseLeave += o => { UserCon.BackgroundColor = Color4.LightGray; return Task.CompletedTask; };
UserCon.Clicked += UserConOnClicked;
titlecon.Controls.Add(UserCon);
}
LuskiExperiments.GUI.MemberList.EventToggled += MemberListOnEventToggled;
titlecon.ForceDistanceUpdate(this);
titlecon.Controls.Add(title = new Label(Globals.DefaultFont)
{
//Location = new(
});
titlecon.Controls.Add(desc = new Label(Globals.DefaultFont)
{
Color = new(161,161,161,255),
Location = new(title.Location.X + title.Size.X + 5, title.Location.Y, 0)
});
Controls.Add(tb = new()
{
// InsideColor = new(28, 28, 28, 255),
//BorderColor = Color4.DarkCyan,
Location = new(10.ScaleInt(), 824.ScaleInt(), 0),
Size = new(960.ScaleInt(), 34.ScaleInt()),
Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left | ObjectAnchor.Right,
HoverMouse = MouseCursor.IBeam,
//Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
//Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.Red,
TextLocation = TextLocation.LineCenter
});
tb.KeyPress += TbOnKeyPress;
tb.OnRemoveLine += TbOnOnRemoveLine;
tb.OnNewLine += TbOnOnNewLine;
tb.ForceDistanceUpdate(this);
//tb.KeyPress += TbOnKeyPress;
//Globals.Luski.MainServer.MessageReceived += LuskiOnMessageReceived;
}
private bool ssss = false;
private Task OnSizeChanged(IRenderObject arg)
{
if (ssss) return Task.CompletedTask;
ssss = true;
BlockDraw = true;
bool off = false;
for (int j = 0; j < MessageFlow.Controls.Length; j++)
{
if (MessageFlow.Controls[j] is ChatMessage cm && cm.Controls.Length != 0 && cm.Location.Y + cm.Size.Y >= 0 && !off)
{
if (cm.MessageObjs[0] is Label First)
{
First.MaxSize = new(MessageFlow.Size.X - First.Location.X - 10.ScaleInt(), Int32.MaxValue);
First.ForceDistanceUpdate(cm);
}
for (int i = 1; i < cm.MessageObjs.Count; i++)
{
cm.MessageObjs[i].Location = new(cm.MessageObjs[i].Location.X,
cm.MessageObjs[i - 1].Location.Y + cm.MessageObjs[i - 1].Size.Y,
cm.MessageObjs[i].Location.Z);
cm.MessageObjs[i].ForceDistanceUpdate(cm);
if (cm.MessageObjs[i] is Label l)
{
l.MaxSize = new(MessageFlow.Size.X - l.Location.X - 10.ScaleInt(), Int32.MaxValue);
//l.Text = l.Text;
}
}
int ny = cm.MessageObjs.Last().Size.Y + cm.MessageObjs.Last().Location.Y + (int)cm.VerticalPadding;
if (cm.Location.Y + ny > MessageFlow.Size.Y) off = true;
if (cm.Size.Y != ny)
{
cm.Size = new(Size.X, ny);
MessageFlow.ReportSizeUpdate(cm);
}
ssss = false;
}
}
BlockDraw = false;
return Task.CompletedTask;
}
private async Task MessageFlowOnFlowUpdate(bool arg1, uint arg2, uint arg3)
{
if (!loadingm && arg1 && arg3 == 0 && (arg2 != 0 || MessageFlow.MaxScrollValue == 0))
{
loadingm = true;
var messages = await Channel!.GetMessages(CancellationToken.None, first!, Globals.Settings.LoadPerChannel);
if (messages.Count == 0) return;
index = 0;
fakeIndex = false;
lastmIndex = null;
lastUserIndex = null;
LastChatMessageIndex = null;
await AddMessagesIndex(messages);
MessageFlow.ForceScrollUpdate();
first = messages.Last();
if (Globals.Settings.LoadPerChannel == messages.Count)loadingm = false;
}
}
private async Task TbOnKeyPress(KeyboardKeyEventArgs arg)
{
if (arg.Key == Keys.Enter && !arg.Shift)
{
await Channel!.SendMessage(tb.Text);
tb.Text = string.Empty;
tb.CursorLocation = 0;
}
}
private Task TbOnOnRemoveLine()
{
BlockDraw = true;
tb.Location = new(tb.Location.X, tb.Location.Y + (int)tb.Font.PixelHeight, 0);
MessageFlow.Size = new(MessageFlow.Size.X, MessageFlow.Size.Y + (int)tb.Font.PixelHeight);
BlockDraw = false;
return Task.CompletedTask;
}
private Task TbOnOnNewLine()
{
BlockDraw = true;
tb.Location = new(tb.Location.X, tb.Location.Y - (int)tb.Font.PixelHeight, 0);
MessageFlow.Size = new(MessageFlow.Size.X, MessageFlow.Size.Y - (int)tb.Font.PixelHeight);
BlockDraw = false;
return Task.CompletedTask;
}
private async Task MemberListOnEventToggled(bool arg)
{
if (arg)
{
UserCon =
new(Globals.ms.TextureManager.GetTextureResource("person.png"))
{
Size = new(24.ScaleInt()),
Location = new(base.Size.X - 36.ScaleInt(), 12.ScaleInt(),0),
Anchor = ObjectAnchor.Right | ObjectAnchor.Top,
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.LightGray
};
UserCon.MouseEnter += o => { UserCon.BackgroundColor = Color4.White; return Task.CompletedTask; };
UserCon.MouseLeave += o => { UserCon.BackgroundColor = Color4.LightGray; return Task.CompletedTask; };
UserCon.Clicked += UserConOnClicked;
titlecon.Controls.Add(UserCon);
}
else
{
if (um_open) await UserConOnClicked(UserCon!);
titlecon.Controls.Remove(UserCon!);
UserCon = null;
}
}
private bool um_open = false;
private bool SeperateOffline = true;
private async Task UserConOnClicked(IRenderObject arg)
{
um_open = !um_open;
if (um_open)
{
if (memberflow is null)
{
int x = 232.ScaleInt();
memberflow = new()
{
BackgroundColor = new(34, 34, 34, 255),
Size = new(x, Size.Y - titlecon.Size.Y),
Location = new(Size.X - x, titlecon.Size.Y, 0),
Anchor = ObjectAnchor.Top | ObjectAnchor.Right | ObjectAnchor.Bottom
};
memberflow.ForceDistanceUpdate(this);
Controls.Add(memberflow);
}
if (memberflow.Controls.Length == 0)
{
Dictionary<long, RoleView> Roles = new();
RoleView? Offline = null;
Dictionary<long, RoleView> Users = new();
foreach (var m in (await Channel!.GetMembers()))
{
Role top_role = (await m.GetRoles())[0];
if (m.Status == UserStatus.Offline && SeperateOffline)
{
if (Offline is null)
{
Offline = new();
memberflow.Controls.Add(Offline);
}
await Offline.AddUser(m, top_role);
Users.Add(m.Id, Offline);
memberflow.ReportSizeUpdate(Offline);
}
else
{
if (!Roles.ContainsKey(top_role.ID))
{
Roles.Add(top_role.ID, new(top_role));
int _index_ = 0;
for (int index_ = memberflow.Controls.Length-1; index_ >= 0; index_--)
{
RoleView r = ((RoleView)memberflow.Controls[index_]);
if (r.r is null) continue;
if (r.r.Index > top_role.Index)
{
_index_ = index_ + 1;
break;
}
}
memberflow.Controls.Insert(_index_, Roles[top_role.ID]);
}
await Roles[top_role.ID].AddUser(m, top_role);
Users.Add(m.Id, Roles[top_role.ID]);
memberflow.ReportSizeUpdate(Roles[top_role.ID]);
}
}
Channel!.Server.StatusUpdate += async (status, user) =>
{
if (!SeperateOffline && !Users.ContainsKey(user.Id)) return;
Role top_role2 = (await user.GetRoles())[0];
Globals.ms.Invoke(async () =>
{
if (status == UserStatus.Offline && user.Status != UserStatus.Offline)
{
Offline!.RemoveUser(user.Id);
if (Offline.i == 0)
{
memberflow.Controls.Remove(Offline);
}
if (!Roles.ContainsKey(top_role2.ID))
{
Roles.Add(top_role2.ID, new(top_role2));
int _index_ = 0;
for (int index_ = memberflow.Controls.Length-1; index_ >= 0; index_--)
{
RoleView r = ((RoleView)memberflow.Controls[index_]);
if (r.r is null) continue;
if (r.r.Index > top_role2.Index)
{
_index_ = index_ + 1;
break;
}
}
memberflow.Controls.Insert(_index_, Roles[top_role2.ID]);
}
await Roles[top_role2.ID].AddUser(user, top_role2);
memberflow.ReportSizeUpdate(Roles[top_role2.ID]);
if (Offline is not null) memberflow.ReportSizeUpdate(Offline);
Users[user.Id] = Roles[top_role2.ID];
}
if (status != UserStatus.Offline && user.Status == UserStatus.Offline)
{
Users[user.Id].RemoveUser(user.Id);
if (Users[user.Id].i == 0)
{
if (Roles.ContainsKey(top_role2.ID)) Roles.Remove(top_role2.ID);
memberflow.Controls.Remove(Users[user.Id]);
}
if (Offline is null)
{
Offline = new();
memberflow.Controls.Add(Offline);
}
await Offline.AddUser(user, top_role2);
memberflow.ReportSizeUpdate(Offline);
memberflow.ReportSizeUpdate(Users[user.Id]);
Users[user.Id] = Offline;
}
Globals.ms.DrawFrame();
});
};
}
TryDraw();
memberflow.Visible = true;
MessageFlow.Size = new(MessageFlow.Size.X - memberflow.Size.X, MessageFlow.Size.Y);
MessageFlow.ForceDistanceUpdate(this);
tb.Size = new(tb.Size.X - memberflow.Size.X, tb.Size.Y);
tb.ForceDistanceUpdate();
}
else
{
memberflow!.Visible = false;
MessageFlow.Size = new(MessageFlow.Size.X + memberflow.Size.X, MessageFlow.Size.Y);
MessageFlow.ForceDistanceUpdate(this);
tb.Size = new(tb.Size.X + memberflow.Size.X, tb.Size.Y);
tb.ForceDistanceUpdate();
}
}
private SocketMessage? lastm;
private long? lastUser;
private bool fake = false;
public ChatMessage? LastChatMessage;
private SocketMessage? lastmIndex;
private long? lastUserIndex;
private bool fakeIndex = false;
public ChatMessage? LastChatMessageIndex;
private bool loadingm = false;
public async Task LoadChannel(SocketChannel channel)
{
Channel = channel;
if (memberflow is not null)
{
BlockDraw = true;
await UserConOnClicked(UserCon!);
memberflow.Controls.Clear();
await UserConOnClicked(UserCon!);
BlockDraw = false;
}
title.Text = channel.Name;
var five = 5.ScaleInt();
title.Location = new(five + five,
(titlecon.Size.Y - ((int)(title.Font.PixelHeight * ((float)title.Font.CurrentFonts[0].Face.Height /
title.Font.CurrentFonts[0].Face.UnitsPerEM)))) / 2,
title.Location.Z);
desc.Text = channel.Description;
desc.Location = new((int)(title.Location.X + title.Size.X + five),
(titlecon.Size.Y - ((int)(desc.Font.PixelHeight * ((float)desc.Font.CurrentFonts[0].Face.Height /
desc.Font.CurrentFonts[0].Face.UnitsPerEM)))) / 2,
desc.Location.Z);
if (Window is not null)
{
Window.Title = $"{channel.Name} | {channel.Server.Name} - Luski";
}
tb.WatermarkText = $"Message {channel.Name}";
tb.Text = "";
tb.CursorLocation = 0;
tb.Focus();
}
public void ClearChat()
{
MessageFlow.Controls.Clear();
MessageFlow.ScrollUpdatesInterval = 33;
lastm = null;
lastUser = null;
LastChatMessage = null;
first = null;
}
public async Task AddMessages(IEnumerable<SocketMessage> messages, bool reverse = true)
{
MessageFlow.BlockDraw = true;
if (reverse)
{
foreach (SocketMessage message in messages.Reverse())
{
await AddMessage(message);
}
}
else
{
foreach (SocketMessage message in messages)
{
await AddMessage(message);
}
}
MessageFlow.BlockDraw = false;
}
public async Task AddMessagesIndex(IEnumerable<SocketMessage> messages)
{
MessageFlow.BlockDraw = true;
index = 0;
foreach (SocketMessage message in messages.Reverse())
{
await AddMessageIndex(message);
}
MessageFlow.BlockDraw = false;
}
public async Task AddMessage(SocketMessage Message, bool scrool = false)
{
if (first is null) first = Message;
bool hasbeentenmin = false;
if (lastm is not null)
hasbeentenmin =
Channel!.Epoch.AddMilliseconds(lastm.ID >> 22).ToLocalTime().AddMinutes(10) <
Channel!.Epoch.AddMilliseconds(Message.ID >> 22).ToLocalTime();
lastm = Message;
if (lastUser is null || lastUser != Message.AuthorID || hasbeentenmin || fake != Message.IsProfile)
{
if (Window is null || !Globals.ms.InvokeRequired)
{
MessageFlow.Controls.Add(LastChatMessage = await ChatMessage.MakeChatMessage(this, Message));
if (scrool) MessageFlow.ScrollToBottom();
}
else
{
LastChatMessage = await ChatMessage.MakeChatMessage(this, Message);
Globals.ms.Invoke(() =>
{
MessageFlow.Controls.Add(LastChatMessage);
if (scrool) MessageFlow.ScrollToBottom();
Window.TryDraw();
});
}
}
else
{
if (Window is null || !Globals.ms.InvokeRequired)
{
await LastChatMessage!.AddMessage(Message);
if (scrool) MessageFlow.ScrollToBottom();
}
else
{
Globals.ms.Invoke(() =>
{
LastChatMessage!.AddMessage(Message);
if (scrool) MessageFlow.ScrollToBottom();
Window!.TryDraw();
});
}
}
fake = Message.IsProfile;
lastUser = Message.AuthorID;
}
private int index = 0;
public async Task AddMessageIndex(SocketMessage Message)
{
bool hasbeentenmin = false;
if (lastmIndex is not null)
hasbeentenmin =
Channel!.Epoch.AddMilliseconds(lastmIndex.ID >> 22).ToLocalTime().AddMinutes(10) <
Channel!.Epoch.AddMilliseconds(Message.ID >> 22).ToLocalTime();
lastmIndex = Message;
if (lastUserIndex is null || lastUserIndex != Message.AuthorID || hasbeentenmin || fake != Message.IsProfile)
{
if (Window is null || !Globals.ms.InvokeRequired)
{
MessageFlow.Controls.Insert(index, LastChatMessageIndex = await ChatMessage.MakeChatMessage(this, Message));
LastChatMessageIndex.LoadToParent(MessageFlow, Globals.ms);
index++;
}
else
{
LastChatMessageIndex = await ChatMessage.MakeChatMessage(this, Message);
Globals.ms.Invoke(() =>
{
MessageFlow.Controls.Insert(index, LastChatMessageIndex);
LastChatMessageIndex.LoadToParent(MessageFlow, Globals.ms);
index++;
Window.TryDraw();
});
}
}
else
{
if (Window is null || !Globals.ms.InvokeRequired)
{
await LastChatMessageIndex!.AddMessage(Message);
}
else
{
Globals.ms.Invoke(() =>
{
LastChatMessageIndex!.AddMessage(Message);
Window!.TryDraw();
});
}
}
fakeIndex = Message.IsProfile;
lastUserIndex = Message.AuthorID;
}
}