Add ahelp typing indicator for admins (#19060)
* Add ahelp typing indicator for admins * Lower typing updates throttle from 3 seconds to 1 * Add stopping typing when sending a message * Lower typing indicator timeout from 15 to 10 seconds
This commit is contained in:
@@ -2,13 +2,17 @@
|
||||
using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Administration.Systems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class BwoinkSystem : SharedBwoinkSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public event EventHandler<BwoinkTextMessage>? OnBwoinkTextMessageRecieved;
|
||||
private (TimeSpan Timestamp, bool Typing) _lastTypingUpdateSent;
|
||||
|
||||
protected override void OnBwoinkTextMessage(BwoinkTextMessage message, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
@@ -20,6 +24,19 @@ namespace Content.Client.Administration.Systems
|
||||
// Reuse the channel ID as the 'true sender'.
|
||||
// Server will ignore this and if someone makes it not ignore this (which is bad, allows impersonation!!!), that will help.
|
||||
RaiseNetworkEvent(new BwoinkTextMessage(channelId, channelId, text));
|
||||
SendInputTextUpdated(channelId, false);
|
||||
}
|
||||
|
||||
public void SendInputTextUpdated(NetUserId channel, bool typing)
|
||||
{
|
||||
if (_lastTypingUpdateSent.Typing == typing &&
|
||||
_lastTypingUpdateSent.Timestamp + TimeSpan.FromSeconds(1) > _timing.RealTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastTypingUpdateSent = (_timing.RealTime, typing);
|
||||
RaiseNetworkEvent(new BwoinkClientTypingUpdated(channel, typing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
Orientation="Vertical"
|
||||
HorizontalExpand="True">
|
||||
<OutputPanel Name="TextOutput" VerticalExpand="true" />
|
||||
<RichTextLabel Name="TypingIndicator" Access="Public" />
|
||||
<HistoryLineEdit Name="SenderLineEdit" />
|
||||
<RichTextLabel Name="RelayedToDiscordLabel" Access="Public" Visible="False" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.Bwoink
|
||||
@@ -13,6 +14,8 @@ namespace Content.Client.Administration.UI.Bwoink
|
||||
|
||||
public int Unread { get; private set; } = 0;
|
||||
public DateTime LastMessage { get; private set; } = DateTime.MinValue;
|
||||
private List<string> PeopleTyping { get; set; } = new();
|
||||
public event Action<string>? InputTextChanged;
|
||||
|
||||
public BwoinkPanel(Action<string> messageSender)
|
||||
{
|
||||
@@ -32,6 +35,8 @@ namespace Content.Client.Administration.UI.Bwoink
|
||||
Unread = 0;
|
||||
};
|
||||
SenderLineEdit.OnTextEntered += Input_OnTextEntered;
|
||||
SenderLineEdit.OnTextChanged += Input_OnTextChanged;
|
||||
UpdateTypingIndicator();
|
||||
}
|
||||
|
||||
private void Input_OnTextEntered(LineEdit.LineEditEventArgs args)
|
||||
@@ -43,6 +48,11 @@ namespace Content.Client.Administration.UI.Bwoink
|
||||
SenderLineEdit.Clear();
|
||||
}
|
||||
|
||||
private void Input_OnTextChanged(LineEdit.LineEditEventArgs args)
|
||||
{
|
||||
InputTextChanged?.Invoke(args.Text);
|
||||
}
|
||||
|
||||
public void ReceiveLine(SharedBwoinkSystem.BwoinkTextMessage message)
|
||||
{
|
||||
if (!Visible)
|
||||
@@ -53,5 +63,54 @@ namespace Content.Client.Administration.UI.Bwoink
|
||||
TextOutput.AddMessage(formatted);
|
||||
LastMessage = message.SentAt;
|
||||
}
|
||||
|
||||
private void UpdateTypingIndicator()
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
msg.PushColor(Color.LightGray);
|
||||
|
||||
var text = PeopleTyping.Count == 0
|
||||
? string.Empty
|
||||
: Loc.GetString("bwoink-system-typing-indicator",
|
||||
("players", string.Join(", ", PeopleTyping)),
|
||||
("count", PeopleTyping.Count));
|
||||
|
||||
msg.AddText(text);
|
||||
msg.Pop();
|
||||
|
||||
TypingIndicator.SetMessage(msg);
|
||||
}
|
||||
|
||||
public void UpdatePlayerTyping(string name, bool typing)
|
||||
{
|
||||
if (typing)
|
||||
{
|
||||
if (PeopleTyping.Contains(name))
|
||||
return;
|
||||
|
||||
PeopleTyping.Add(name);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(10), () =>
|
||||
{
|
||||
if (Disposed)
|
||||
return;
|
||||
|
||||
PeopleTyping.Remove(name);
|
||||
UpdateTypingIndicator();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
PeopleTyping.Remove(name);
|
||||
}
|
||||
|
||||
UpdateTypingIndicator();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
InputTextChanged = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<BwoinkDiscordRelayUpdated>(DiscordRelayUpdated);
|
||||
SubscribeNetworkEvent<BwoinkPlayerTypingUpdated>(PeopleTypingUpdated);
|
||||
}
|
||||
|
||||
public void OnStateEntered(GameplayState state)
|
||||
@@ -144,6 +145,11 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
|
||||
UIHelper?.DiscordRelayChanged(_discordRelayActive);
|
||||
}
|
||||
|
||||
private void PeopleTypingUpdated(BwoinkPlayerTypingUpdated args, EntitySessionEventArgs session)
|
||||
{
|
||||
UIHelper?.PeopleTypingUpdated(args);
|
||||
}
|
||||
|
||||
public void EnsureUIHelper()
|
||||
{
|
||||
var isAdmin = _adminManager.HasFlag(AdminFlags.Adminhelp);
|
||||
@@ -157,6 +163,7 @@ public sealed class AHelpUIController: UIController, IOnStateChanged<GameplaySta
|
||||
UIHelper.DiscordRelayChanged(_discordRelayActive);
|
||||
|
||||
UIHelper.SendMessageAction = (userId, textMessage) => _bwoinkSystem?.Send(userId, textMessage);
|
||||
UIHelper.InputTextChanged += (channel, text) => _bwoinkSystem?.SendInputTextUpdated(channel, text.Length > 0);
|
||||
UIHelper.OnClose += () => { SetAHelpPressed(false); };
|
||||
UIHelper.OnOpen += () => { SetAHelpPressed(true); };
|
||||
SetAHelpPressed(UIHelper.IsOpen);
|
||||
@@ -242,9 +249,11 @@ public interface IAHelpUIHandler : IDisposable
|
||||
public void Open(NetUserId netUserId, bool relayActive);
|
||||
public void ToggleWindow();
|
||||
public void DiscordRelayChanged(bool active);
|
||||
public void PeopleTypingUpdated(BwoinkPlayerTypingUpdated args);
|
||||
public event Action OnClose;
|
||||
public event Action OnOpen;
|
||||
public Action<NetUserId, string>? SendMessageAction { get; set; }
|
||||
public event Action<NetUserId, string>? InputTextChanged;
|
||||
}
|
||||
public sealed class AdminAHelpUIHandler : IAHelpUIHandler
|
||||
{
|
||||
@@ -319,9 +328,16 @@ public sealed class AdminAHelpUIHandler : IAHelpUIHandler
|
||||
{
|
||||
}
|
||||
|
||||
public void PeopleTypingUpdated(BwoinkPlayerTypingUpdated args)
|
||||
{
|
||||
if (_activePanelMap.TryGetValue(args.Channel, out var panel))
|
||||
panel.UpdatePlayerTyping(args.PlayerName, args.Typing);
|
||||
}
|
||||
|
||||
public event Action? OnClose;
|
||||
public event Action? OnOpen;
|
||||
public Action<NetUserId, string>? SendMessageAction { get; set; }
|
||||
public event Action<NetUserId, string>? InputTextChanged;
|
||||
|
||||
public void Open(NetUserId channelId, bool relayActive)
|
||||
{
|
||||
@@ -367,6 +383,7 @@ public sealed class AdminAHelpUIHandler : IAHelpUIHandler
|
||||
return existingPanel;
|
||||
|
||||
_activePanelMap[channelId] = existingPanel = new BwoinkPanel(text => SendMessageAction?.Invoke(channelId, text));
|
||||
existingPanel.InputTextChanged += text => InputTextChanged?.Invoke(channelId, text);
|
||||
existingPanel.Visible = false;
|
||||
if (!Control!.BwoinkArea.Children.Contains(existingPanel))
|
||||
Control.BwoinkArea.AddChild(existingPanel);
|
||||
@@ -445,9 +462,14 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
|
||||
}
|
||||
}
|
||||
|
||||
public void PeopleTypingUpdated(BwoinkPlayerTypingUpdated args)
|
||||
{
|
||||
}
|
||||
|
||||
public event Action? OnClose;
|
||||
public event Action? OnOpen;
|
||||
public Action<NetUserId, string>? SendMessageAction { get; set; }
|
||||
public event Action<NetUserId, string>? InputTextChanged;
|
||||
|
||||
public void Open(NetUserId channelId, bool relayActive)
|
||||
{
|
||||
@@ -460,6 +482,7 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
|
||||
if (_window is { Disposed: false })
|
||||
return;
|
||||
_chatPanel = new BwoinkPanel(text => SendMessageAction?.Invoke(_ownerId, text));
|
||||
_chatPanel.InputTextChanged += text => InputTextChanged?.Invoke(_ownerId, text);
|
||||
_chatPanel.RelayedToDiscordLabel.Visible = relayActive;
|
||||
_window = new DefaultWindow()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user