add color to server

This commit is contained in:
Benjamin Palko 2025-05-22 14:19:37 -04:00
parent c89ba23134
commit 4f8fd9dc18
5 changed files with 118 additions and 24 deletions

17
client/UserUtils.cs Normal file
View file

@ -0,0 +1,17 @@
using Godot;
using SpacetimeDB.Types;
public static class UserUtils
{
public static Color ParseColor(User user)
{
return user.Color != null && Color.HtmlIsValid(user.Color)
? Color.FromHtml(user.Color)
: Colors.AliceBlue;
}
public static string UserNameOrIdentity(User user)
{
return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown";
}
}

1
client/UserUtils.cs.uid Normal file
View file

@ -0,0 +1 @@
uid://dnaxnse8ipje0

View file

@ -4,7 +4,7 @@ using SpacetimeDB.Types;
public partial class ChatLog : RichTextLabel public partial class ChatLog : RichTextLabel
{ {
const string SystemColor = "#747474"; private static readonly Color SystemColor = Colors.Gray;
public override void _EnterTree() public override void _EnterTree()
{ {
@ -17,14 +17,9 @@ public partial class ChatLog : RichTextLabel
RegisterSubscriptions(conn); RegisterSubscriptions(conn);
} }
string UserNameOrIdentity(User user) void PushMessage(string name, string message, Color color)
{ {
return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown"; string entry = $"[color={color.ToHtml()}]{name}:[/color] {message}";
}
void PushMessage(string name, string message, string color)
{
string entry = $"[color={color}]{name}:[/color] {message}";
this.Text += $"{entry}\n"; this.Text += $"{entry}\n";
} }
@ -47,7 +42,11 @@ public partial class ChatLog : RichTextLabel
{ {
return; return;
} }
PushMessage("System", $"{UserNameOrIdentity(insertedValue)} connected", SystemColor); PushMessage(
"System",
$"{UserUtils.UserNameOrIdentity(insertedValue)} connected",
SystemColor
);
} }
void User_OnUpdate(EventContext ctx, User oldValue, User newValue) void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
@ -56,7 +55,7 @@ public partial class ChatLog : RichTextLabel
{ {
PushMessage( PushMessage(
"System", "System",
$"{UserNameOrIdentity(oldValue)} renamed to {UserNameOrIdentity(newValue)}", $"{UserUtils.UserNameOrIdentity(oldValue)} renamed to {UserUtils.UserNameOrIdentity(newValue)}",
SystemColor SystemColor
); );
} }
@ -64,11 +63,19 @@ public partial class ChatLog : RichTextLabel
{ {
if (newValue.Online) if (newValue.Online)
{ {
PushMessage("System", $"{UserNameOrIdentity(newValue)} connected", SystemColor); PushMessage(
"System",
$"{UserUtils.UserNameOrIdentity(newValue)} connected",
SystemColor
);
} }
else else
{ {
PushMessage("System", $"{UserNameOrIdentity(newValue)} disconnected", SystemColor); PushMessage(
"System",
$"{UserUtils.UserNameOrIdentity(newValue)} disconnected",
SystemColor
);
} }
} }
} }
@ -76,12 +83,12 @@ public partial class ChatLog : RichTextLabel
void Message_OnInsert(EventContext ctx, Message insertedValue) void Message_OnInsert(EventContext ctx, Message insertedValue)
{ {
User sender = ctx.Db.User.Identity.Find(insertedValue.Sender); User sender = ctx.Db.User.Identity.Find(insertedValue.Sender);
string color = sender.Identity.Equals(Spacetime.Instance.Identity) ? "blue" : "red"; Color color = ctx.Identity == sender.Identity ? UserUtils.ParseColor(sender) : Colors.Red;
if (ctx.Event is Event<Reducer>.SubscribeApplied) if (ctx.Event is Event<Reducer>.SubscribeApplied)
{ {
PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); PushMessage(UserUtils.UserNameOrIdentity(sender), insertedValue.Text, color);
return; return;
} }
PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); PushMessage(UserUtils.UserNameOrIdentity(sender), insertedValue.Text, color);
} }
} }

View file

@ -12,8 +12,10 @@ public partial class ChatOptions : HBoxContainer
Username = GetNode<LineEdit>("Username"); Username = GetNode<LineEdit>("Username");
ColorPicker = GetNode<ColorPickerButton>("ColorPicker"); ColorPicker = GetNode<ColorPickerButton>("ColorPicker");
Username.TextSubmitted += OnUsernameInput; Username.TextSubmitted += OnUsernameChanged;
Username.FocusExited += ResetUsername; Username.FocusExited += ResetUsername;
ColorPicker.ColorChanged += OnColorChange;
} }
public override void _Ready() public override void _Ready()
@ -22,24 +24,52 @@ public partial class ChatOptions : HBoxContainer
RegisterSubscriptions(conn); RegisterSubscriptions(conn);
} }
string UserNameOrIdentity(User user)
{
return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown";
}
void ResetUsername() void ResetUsername()
{ {
Username.Text = UserNameOrIdentity(Spacetime.Instance.Me); Username.Text = UserUtils.UserNameOrIdentity(Spacetime.Instance.Me);
} }
void OnUsernameInput(string text) void OnUsernameChanged(string text)
{ {
Spacetime.Instance.Connection.Reducers.SetName(text); Spacetime.Instance.Connection.Reducers.SetName(text);
} }
void OnColorChange(Color color)
{
Spacetime.Instance.Connection.Reducers.SetColor(color.ToHtml(false));
}
void RegisterSubscriptions(DbConnection conn) void RegisterSubscriptions(DbConnection conn)
{ {
conn.Db.User.OnInsert += User_OnInsert;
conn.Db.User.OnUpdate += User_OnUpdate;
conn.Reducers.OnSetName += Reducer_OnSetNameEvent; conn.Reducers.OnSetName += Reducer_OnSetNameEvent;
conn.Reducers.OnSetColor += Reducer_OnSetColorEvent;
}
void User_OnInsert(EventContext ctx, User insertedValue)
{
// It's me
if (ctx.Identity == insertedValue.Identity)
{
Username.Text = insertedValue.Name;
ColorPicker.Color =
insertedValue.Color != null && Color.HtmlIsValid(insertedValue.Color)
? Color.FromHtml(insertedValue.Color)
: Colors.AliceBlue;
}
}
void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
{
if (ctx.Identity == oldValue.Identity && ctx.Identity == newValue.Identity)
{
Username.Text = newValue.Name;
ColorPicker.Color =
newValue.Color != null && Color.HtmlIsValid(newValue.Color)
? Color.FromHtml(newValue.Color)
: Colors.AliceBlue;
}
} }
/// Our `OnSetNameEvent` callback: print a warning if the reducer failed. /// Our `OnSetNameEvent` callback: print a warning if the reducer failed.
@ -57,4 +87,19 @@ public partial class ChatOptions : HBoxContainer
return; return;
} }
} }
void Reducer_OnSetColorEvent(ReducerEventContext ctx, string color)
{
var e = ctx.Event;
if (e.CallerIdentity != Spacetime.Instance.Identity)
{
// Not me
return;
}
if (e.Status is Status.Failed(var error))
{
GD.PrintErr($"Failed to change color to {color}: {error}");
return;
}
}
} }

View file

@ -1,3 +1,4 @@
using System.Text.RegularExpressions;
using SpacetimeDB; using SpacetimeDB;
public static partial class Module public static partial class Module
@ -8,6 +9,7 @@ public static partial class Module
[PrimaryKey] [PrimaryKey]
public Identity Identity; public Identity Identity;
public string? Name; public string? Name;
public string? Color;
public bool Online; public bool Online;
} }
@ -42,6 +44,29 @@ public static partial class Module
return name; return name;
} }
[Reducer]
public static void SetColor(ReducerContext ctx, string color)
{
color = ValidateColor(color);
var user = ctx.Db.User.Identity.Find(ctx.Sender);
if (user is not null)
{
user.Color = color;
ctx.Db.User.Identity.Update(user);
}
}
private static string ValidateColor(string color)
{
var regex = new Regex("^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
if (!regex.IsMatch(color))
{
throw new Exception("Invalid color code");
}
return color;
}
[Reducer] [Reducer]
public static void SendMessage(ReducerContext ctx, string text) public static void SendMessage(ReducerContext ctx, string text)
{ {
@ -113,4 +138,3 @@ public static partial class Module
} }
} }
} }