Editor/Dock/OrgRosterCard.cs
using System;
using System.Collections.Generic;
using Editor;
using Sandbox;
using Sandbox.UI;
namespace TeamCreate;
public sealed class OrgRosterCard : DockCard
{
private sealed class MemberRow : Widget
{
private readonly OrgRosterCard owner;
private readonly OrgMemberInfo member;
private readonly bool isSelf;
private string lastStatus;
public MemberRow(OrgRosterCard owner, Widget parent, OrgMemberInfo member, bool isSelf)
: base(parent)
{
this.owner = owner;
this.member = member;
this.isSelf = isSelf;
FixedHeight = 40f;
ToolTip = ToolTipFor(StatusOf(owner.IsInSession(member.SteamId)));
lastStatus = StatusOf(owner.IsInSession(member.SteamId));
OnPaintOverride = PaintRow;
MouseClick = OpenProfile;
}
public void SyncStatus(OrgRosterCard owner)
{
string text = StatusOf(owner.IsInSession(member.SteamId));
if (!string.Equals(text, lastStatus, StringComparison.Ordinal))
{
lastStatus = text;
ToolTip = ToolTipFor(text);
}
}
private string StatusOf(bool inSession)
{
string result;
if (inSession)
{
result = "In this session";
}
else
{
result = (member.Online ? "Steam online" : "Offline");
}
return result;
}
private string ToolTipFor(string status)
{
string text = (string.IsNullOrWhiteSpace(member.Name) ? "(unknown name)" : member.Name);
string text2 = text + "\nSteamId: " + member.SteamId + "\n" + status;
if (!isSelf && !member.IsFriend)
{
text2 += "\nNot a Steam friend — they cannot join this session.";
}
return text2 + "\nClick to open the Steam profile.";
}
private void OpenProfile()
{
if (ulong.TryParse(member.SteamId, out var result))
{
new Friend(result).OpenInOverlay();
}
}
private bool PaintRow()
{
Rect rect = LocalRect;
if (Paint.HasMouseOver)
{
Paint.SetBrush(Theme.Text.WithAlpha(0.05f));
Paint.DrawRect(in rect, 4f);
}
bool flag = owner.IsInSession(member.SteamId);
Rect rect2 = new Rect(rect.Left + 4f, rect.Top + (rect.Height - 32f) * 0.5f, 32f, 32f);
DockTheme.DrawAvatar(rect2, member.SteamId, member.Name, flag, member.Online, !isSelf && !member.IsFriend);
string text = (string.IsNullOrWhiteSpace(member.Name) ? "(unknown name)" : member.Name);
if (isSelf)
{
text += " (you)";
}
string text2 = StatusOf(flag);
float num = Paint.MeasureText(text2).x + 14f;
float x = rect.Left + 32f + 14f;
float width = MathF.Max(0f, rect.Right - x - num - 14f);
Paint.SetPen(in Theme.Text, 0f, PenStyle.Solid);
Paint.DrawText(new Rect(in x, rect.Top, in width, rect.Height), Paint.GetElidedText(text, width), TextFlag.LeftCenter | TextFlag.SingleLine);
if (!isSelf && !member.IsFriend)
{
Paint.SetBrush(DockTheme.WarningColor);
Paint.ClearPen();
Paint.DrawCircle(new Vector2(rect.Right - num - 4f, rect.Top + rect.Height * 0.5f), 3.0);
}
Paint.SetPen(flag ? DockTheme.PeerColor(member.SteamId) : (member.Online ? DockTheme.OkColor : DockTheme.IdleColor), 0f, PenStyle.Solid);
Paint.DrawText(new Rect(rect.Right - num, rect.Top, num - 6f, rect.Height), text2, TextFlag.RightCenter | TextFlag.SingleLine);
return false;
}
}
private static readonly TimeSpan RebuildInterval = TimeSpan.FromSeconds(30L);
private readonly ScrollArea scroll;
private readonly Editor.Label empty;
private readonly List<MemberRow> memberRows = new List<MemberRow>();
private HashSet<string> inSession = new HashSet<string>(StringComparer.Ordinal);
private string selfId;
private int lastRosterCount = -1;
private int lastRevision = -1;
private DateTime nextRebuild;
private bool? hadDirectory;
protected override bool FieldsAssigned => scroll != null && empty != null && memberRows != null;
public OrgRosterCard(Widget parent)
: base(parent, "Organization")
{
empty = Layout.Add(new Editor.Label("", this)
{
WordWrap = true,
Color = DockTheme.MutedColor
});
empty.Visible = false;
scroll = Layout.Add(new ScrollArea(this), 1);
scroll.Canvas = new Widget();
scroll.Canvas.Layout = Layout.Column();
scroll.Canvas.ContentMargins = new Margin(0f, 0f, 8f, 0f);
scroll.Canvas.VerticalSizeMode = SizeMode.Flexible;
scroll.Canvas.HorizontalSizeMode = SizeMode.Flexible;
scroll.HorizontalScrollbarMode = ScrollbarMode.Off;
scroll.Visible = false;
}
public void Refresh()
{
CollaborationSession current = CollaborationSession.Current;
if (selfId == null && LocalSteamIdentity.TryGet(out var identity, out var _, out var _))
{
selfId = SteamIdentityRules.Canonical(identity);
}
if (current.Roster.Count != lastRosterCount)
{
RebuildInSession(current);
}
OrgDirectory organizationDirectory = current.OrganizationDirectory;
bool flag = organizationDirectory != null;
bool flag2 = hadDirectory != flag;
bool flag3 = flag && (organizationDirectory.Revision != lastRevision || DateTime.UtcNow >= nextRebuild);
if (flag2 | flag3)
{
Rebuild(organizationDirectory);
}
foreach (MemberRow memberRow in memberRows)
{
memberRow.SyncStatus(this);
}
}
public bool IsInSession(string steamId)
{
if (string.IsNullOrEmpty(steamId))
{
return false;
}
if (string.Equals(steamId, selfId, StringComparison.Ordinal))
{
return true;
}
return inSession.Contains(steamId);
}
private void RebuildInSession(CollaborationSession session)
{
lastRosterCount = session.Roster.Count;
inSession.Clear();
foreach (Packet value in session.Roster.Values)
{
if (!string.IsNullOrWhiteSpace(value.SteamId))
{
inSession.Add(value.SteamId);
}
}
}
private void Rebuild(OrgDirectory directory)
{
lastRevision = directory?.Revision ?? (-1);
hadDirectory = directory != null;
nextRebuild = DateTime.UtcNow + RebuildInterval;
memberRows.Clear();
scroll.Canvas.Layout.Clear(deleteWidgets: true);
empty.Visible = false;
scroll.Visible = false;
if (directory == null)
{
DockCard.SetText(Title, "Organization");
ShowEmpty("No organization members found. The organization directory is not available yet.");
return;
}
List<OrgMemberInfo> list = new List<OrgMemberInfo>(directory.Members);
DockCard.SetText(Title, "Organization · " + directory.Org + " (" + list.Count + ")");
if (list.Count == 0)
{
ShowEmpty((directory.Revision == 0) ? "No organization members found. Waiting for the organization service to answer." : ("No organization members found. The organization service returned no members for " + directory.Org + "."));
return;
}
list.Sort(CompareMembers);
int num = Math.Min(list.Count, 50);
for (int i = 0; i < num; i++)
{
OrgMemberInfo orgMemberInfo = list[i];
MemberRow item = scroll.Canvas.Layout.Add(new MemberRow(this, scroll.Canvas, orgMemberInfo, IsSelf(orgMemberInfo.SteamId)));
memberRows.Add(item);
}
if (list.Count > num)
{
scroll.Canvas.Layout.Add(new Editor.Label("+" + (list.Count - num) + " more", scroll.Canvas)
{
Color = DockTheme.MutedColor
});
}
scroll.Canvas.Layout.AddStretchCell();
scroll.Visible = true;
scroll.MaximumHeight = MathF.Min((float)num * 40f + 4f, 420f);
}
private void ShowEmpty(string reason)
{
empty.Text = reason;
empty.Visible = true;
}
private bool IsSelf(string steamId)
{
return !string.IsNullOrEmpty(steamId) && string.Equals(steamId, selfId, StringComparison.Ordinal);
}
private int CompareMembers(OrgMemberInfo a, OrgMemberInfo b)
{
bool flag = IsSelf(a.SteamId);
bool flag2 = IsSelf(b.SteamId);
if (flag != flag2)
{
return (!flag) ? 1 : (-1);
}
if (a.Online != b.Online)
{
return (!a.Online) ? 1 : (-1);
}
return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
}
}