Typing indicator (typing chat bubble) (#8215)

This commit is contained in:
Alex Evgrashin
2022-05-17 12:55:19 +03:00
committed by GitHub
parent 2557e45662
commit af926c5279
55 changed files with 678 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
using Content.Shared.CCVar;
using Content.Shared.Chat.TypingIndicator;
using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
namespace Content.Client.Chat.TypingIndicator;
// Client-side typing system tracks user input in chat box
public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
{
[Dependency] private readonly IGameTiming _time = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private readonly TimeSpan _typingTimeout = TimeSpan.FromSeconds(2);
private TimeSpan _lastTextChange;
private bool _isClientTyping;
public override void Initialize()
{
base.Initialize();
_cfg.OnValueChanged(CCVars.ChatShowTypingIndicator, OnShowTypingChanged);
}
public void ClientChangedChatText()
{
// don't update it if player don't want to show typing indicator
if (!_cfg.GetCVar(CCVars.ChatShowTypingIndicator))
return;
// client typed something - show typing indicator
ClientUpdateTyping(true);
_lastTextChange = _time.CurTime;
}
public void ClientSubmittedChatText()
{
// don't update it if player don't want to show typing
if (!_cfg.GetCVar(CCVars.ChatShowTypingIndicator))
return;
// client submitted text - hide typing indicator
ClientUpdateTyping(false);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
// check if client didn't changed chat text box for a long time
if (_isClientTyping)
{
var dif = _time.CurTime - _lastTextChange;
if (dif > _typingTimeout)
{
// client didn't typed anything for a long time - hide indicator
ClientUpdateTyping(false);
}
}
}
private void ClientUpdateTyping(bool isClientTyping)
{
if (_isClientTyping == isClientTyping)
return;
_isClientTyping = isClientTyping;
// check if player controls any pawn
var playerPawn = _playerManager.LocalPlayer?.ControlledEntity;
if (playerPawn == null)
return;
// send a networked event to server
RaiseNetworkEvent(new TypingChangedEvent(playerPawn.Value, isClientTyping));
}
private void OnShowTypingChanged(bool showTyping)
{
// hide typing indicator immediately if player don't want to show it anymore
if (!showTyping)
{
ClientUpdateTyping(false);
}
}
}

View File

@@ -0,0 +1,50 @@
using Content.Shared.Chat.TypingIndicator;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Prototypes;
namespace Content.Client.Chat.TypingIndicator;
public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingIndicatorComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TypingIndicatorComponent, ComponentInit>(OnInit);
}
private void OnInit(EntityUid uid, TypingIndicatorComponent component, ComponentInit args)
{
if (!TryComp(uid, out SpriteComponent? sprite))
return;
if (!_prototypeManager.TryIndex<TypingIndicatorPrototype>(component.Prototype, out var proto))
{
Logger.Error($"Unknown typing indicator id: {component.Prototype}");
return;
}
var layer = sprite.LayerMapReserveBlank(TypingIndicatorLayers.Base);
sprite.LayerSetRSI(layer, proto.SpritePath);
sprite.LayerSetState(layer, proto.TypingState);
sprite.LayerSetShader(layer, proto.Shader);
sprite.LayerSetOffset(layer, proto.Offset);
sprite.LayerSetVisible(layer, false);
}
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
{
base.OnAppearanceChange(uid, component, ref args);
if (!TryComp(uid, out SpriteComponent? sprite))
return;
args.Component.TryGetData(TypingIndicatorVisuals.IsTyping, out bool isTyping);
if (sprite.LayerMapTryGet(TypingIndicatorLayers.Base, out var layer))
{
sprite.LayerSetVisible(layer, isTyping);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Content.Client.Alerts.UI;
using Content.Client.Chat.Managers;
using Content.Client.Chat.TypingIndicator;
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Shared.Chat;
@@ -475,6 +476,9 @@ namespace Content.Client.Chat.UI
{
// Update channel select button to correct channel if we have a prefix.
UpdateChannelSelectButton();
// Warn typing indicator about change
EntitySystem.Get<TypingIndicatorSystem>().ClientChangedChatText();
}
private static ChatSelectChannel GetChannelFromPrefix(char prefix)
@@ -518,6 +522,9 @@ namespace Content.Client.Chat.UI
private void Input_OnTextEntered(LineEdit.LineEditEventArgs args)
{
// Warn typing indicator about entered text
EntitySystem.Get<TypingIndicatorSystem>().ClientSubmittedChatText();
if (!string.IsNullOrWhiteSpace(args.Text))
{
var (prefixChannel, text) = SplitInputContents();