553 lines
21 KiB
C#
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;
|
|
}
|
|
} |