Skip to content

Commit f11d2e7

Browse files
NanoChat QoL And Bug Fixes (#1460)
# Description Fixes notifications so that they always trigger when the chat is not open, fixes a possible exploit where a user can send a message that is longer than the max message length, and improves the UX of NanoChat in a few areas. Original message from Goob-Station/Goob-Station#1313: > Fixed NanoChat message notifications not showing up in situations where you'd definitely expect them to occur. > > Now, for a chat to not send a notification upon a new message, three conditions need to be fulfilled: > - You don't have the chat muted > - Your PDA UI is open > - You have NanoChat as your open program > - Your currently-selected chat is the aforementioned chat More changes: - Validate NanoChat message length & chat name/job title length on the server Goob-Station/Goob-Station@c063001. -If they are too long, they will be truncated to the maximum length. - Improve the UI for editing a chat: - Added a proper icon (used to be the letter E) for the Edit Chat button. ![image](https://github.com/user-attachments/assets/ce868829-a9f5-494b-9d15-2cbc4a7e2a86) - The Edit Chat popup now has correct text: the title is now "Edit a contact", not "Add a new chat" and the Create button has been renamed to the Confirm button. ![image](https://github.com/user-attachments/assets/aabd84b3-0f3c-410a-a74e-06420eb336dc) - Editing a chat no longer deselects the current chat. - This is done by adding a new NanoChatUiMessageType entry, `EditChat` and a new server-side handler function just for chat edits. The previous edit chat method simply *deleted* the chat from the client and created a new one. - Form validation is now more robust: you can now only submit the edit if you've made changes to the name or job title. - Fixed NanoChat not appearing in PDAs with more than 5 pre-installed programs by increasing the PDA disk space (max program count) from 5 to 8, the current disk space in Wizden. ![image](https://github.com/user-attachments/assets/e214fa21-5365-4f8a-8919-c6019d3b94bb) - The job title now appears on the notification title. ![image](https://github.com/user-attachments/assets/486f5b2a-c555-4d1a-97ef-4dab3d8e1102) - The title will be truncated if it's too long. ![image](https://github.com/user-attachments/assets/ef99805c-b004-456a-9b59-e48f4abbe4ab) - Improved form validation on the New Chat popup by only allowing users to submit if the Number field is 4 numbers long. Previously, inputs like "0" "12" "289" were valid which is ultimately incorrect as phone numbers function more like strings that just happen to be digit-only and less like actual numbers. ![image](https://github.com/user-attachments/assets/e3a767ff-71cb-4c61-b3e9-be13af66fd60) - The left chat list will now truncate names and job titles if they're too long. ![image](https://github.com/user-attachments/assets/76a8fbfa-e5e5-495c-ad13-fc9444e6ce9a) ## Changelog :cl: Skubman - add: NanoChat message notifications will now show you the job title of the sender alongside their name. - add: The NanoChat edit button now has a proper icon. - tweak: The disk space (max amount of installable programs) on PDAs has been increased from 5 to 8. This also fixes a bug where NanoChat was not being installed on PDAs with more than 5 pre-installed cartridges. - tweak: The character limit for names and job titles in NanoChat has been increased to their actual limit on ID cards (30 characters). - tweak: NanoChat chat list names/titles and notification titles that are too long will be shortened, indicated with "..." at the end. - tweak: The NanoChat edit popup now displays the correct text, instead of appearing identical to the new chat popup. - fix: NanoChat will now send a new message notification no matter what if you don't have the chat open. - fix: Editing a chat in NanoChat no longer deselects that chat. - fix: Fixed a issue where users could potentially send NanoChat messages longer than the maximum allowed message length. - fix: Fixed being able to create a new chat when you haven't typed in 4 digits in the number field.
1 parent f026528 commit f11d2e7

File tree

14 files changed

+228
-96
lines changed

14 files changed

+228
-96
lines changed

Content.Client/DeltaV/CartridgeLoader/Cartridges/EditChatPopup.xaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<DefaultWindow xmlns="https://spacestation14.io"
2-
Title="{Loc nano-chat-new-title}"
2+
Title="{Loc nano-chat-edit-title}"
33
MinSize="300 200">
44
<PanelContainer StyleClasses="AngleRect">
55
<BoxContainer Orientation="Vertical" Margin="4">
@@ -42,8 +42,8 @@
4242
Text="{Loc nano-chat-cancel}"
4343
StyleClasses="OpenRight"
4444
MinSize="80 0" />
45-
<Button Name="CreateButton"
46-
Text="{Loc nano-chat-create}"
45+
<Button Name="ConfirmButton"
46+
Text="{Loc nano-chat-confirm}"
4747
StyleClasses="OpenLeft"
4848
MinSize="80 0"
4949
Disabled="True" />

Content.Client/DeltaV/CartridgeLoader/Cartridges/EditChatPopup.xaml.cs

+39-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using System.Linq;
2-
using Content.Client.DeltaV.NanoChat;
2+
using Content.Shared.Access.Components;
33
using Robust.Client.AutoGenerated;
44
using Robust.Client.UserInterface.CustomControls;
55
using Robust.Client.UserInterface.XAML;
@@ -9,9 +9,14 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges;
99
[GenerateTypedNameReferences]
1010
public sealed partial class EditChatPopup : DefaultWindow
1111
{
12-
private const int MaxInputLength = 16;
1312
private const int MaxNumberLength = 4;
1413

14+
// Used to see if the user input is different from the original data
15+
// to check if the user can submit
16+
private string _originalNumber = "";
17+
private string _originalName = "";
18+
private string _originalJob = "";
19+
1520
public event Action<uint, string, string?>? OnContactEdited;
1621

1722
public EditChatPopup()
@@ -23,22 +28,23 @@ public EditChatPopup()
2328

2429
// Button handlers
2530
CancelButton.OnPressed += _ => Close();
26-
CreateButton.OnPressed += _ => EditChat();
31+
ConfirmButton.OnPressed += _ => EditChat();
2732

2833
// Input validation
2934
NameInput.OnTextChanged += _ => ValidateInputs();
3035

3136
NameInput.OnTextChanged += args =>
3237
{
33-
if (args.Text.Length > MaxInputLength)
34-
NameInput.Text = args.Text[..MaxInputLength];
38+
if (args.Text.Length > IdCardConsoleComponent.MaxFullNameLength)
39+
NameInput.Text = args.Text[..IdCardConsoleComponent.MaxFullNameLength];
3540
ValidateInputs();
3641
};
3742

3843
JobInput.OnTextChanged += args =>
3944
{
40-
if (args.Text.Length > MaxInputLength)
41-
JobInput.Text = args.Text[..MaxInputLength];
45+
if (args.Text.Length > IdCardConsoleComponent.MaxJobTitleLength)
46+
JobInput.Text = args.Text[..IdCardConsoleComponent.MaxJobTitleLength];
47+
ValidateInputs();
4248
};
4349

4450
NumberInput.OnTextChanged += args =>
@@ -58,10 +64,15 @@ public EditChatPopup()
5864
private void ValidateInputs()
5965
{
6066
var isValid = !string.IsNullOrWhiteSpace(NumberInput.Text) &&
61-
!string.IsNullOrWhiteSpace(NameInput.Text) &&
62-
uint.TryParse(NumberInput.Text, out _);
63-
64-
CreateButton.Disabled = !isValid;
67+
!string.IsNullOrWhiteSpace(NameInput.Text) &&
68+
NumberInput.Text.Length == MaxNumberLength &&
69+
uint.TryParse(NumberInput.Text, out _) &&
70+
// Only valid if there are any changes
71+
(NumberInput.Text != _originalNumber ||
72+
NameInput.Text != _originalName ||
73+
JobInput.Text != _originalJob);
74+
75+
ConfirmButton.Disabled = !isValid;
6576
}
6677

6778
private void EditChat()
@@ -83,7 +94,21 @@ public void ClearInputs()
8394
ValidateInputs();
8495
}
8596

86-
public void SetNumberInput(string newNumber) => NumberInput.Text = newNumber;
87-
public void SetNameInput(string newName) => NameInput.Text = newName;
88-
public void SetJobInput(string newJob) => JobInput.Text = newJob;
97+
public void SetNumberInput(string newNumber)
98+
{
99+
NumberInput.Text = newNumber.PadLeft(MaxNumberLength, '0');
100+
_originalNumber = newNumber;
101+
}
102+
103+
public void SetNameInput(string newName)
104+
{
105+
NameInput.Text = newName;
106+
_originalName = newName;
107+
}
108+
109+
public void SetJobInput(string newJob)
110+
{
111+
JobInput.Text = newJob;
112+
_originalJob = newJob;
113+
}
89114
}

Content.Client/DeltaV/CartridgeLoader/Cartridges/NanoChatEntry.xaml.cs

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges;
88
[GenerateTypedNameReferences]
99
public sealed partial class NanoChatEntry : BoxContainer
1010
{
11+
private const int MaxNameLength = 14;
12+
private const int MaxJobLength = 20;
13+
1114
public event Action<uint>? OnPressed;
1215
private uint _number;
1316
private Action<EventArgs>? _pressHandler;
@@ -29,11 +32,19 @@ public void SetRecipient(NanoChatRecipient recipient, uint number, bool isSelect
2932
_pressHandler = _ => OnPressed?.Invoke(_number);
3033
ChatButton.OnPressed += _pressHandler;
3134

32-
NameLabel.Text = recipient.Name;
33-
JobLabel.Text = recipient.JobTitle ?? "";
35+
NameLabel.Text = Truncate(recipient.Name, MaxNameLength);
36+
JobLabel.Text = Truncate(recipient.JobTitle ?? "", MaxJobLength);
3437
JobLabel.Visible = !string.IsNullOrEmpty(recipient.JobTitle);
3538
UnreadIndicator.Visible = recipient.HasUnread;
3639

3740
ChatButton.ModulateSelfOverride = isSelected ? NanoChatMessageBubble.OwnMessageColor : null;
3841
}
42+
43+
/// <summary>
44+
/// Truncates a string to a maximum length.
45+
/// </summary>
46+
private static string Truncate(string text, int maxLength) =>
47+
text.Length <= maxLength
48+
? text
49+
: text[..(maxLength - 3)] + "...";
3950
}

Content.Client/DeltaV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@
3535
VerticalAlignment="Center"
3636
Margin="0 0 8 0" />
3737
<Button Name="EditChatButton"
38-
Text="E"
3938
MaxSize="32 32"
4039
Visible="False"
4140
StyleClasses="OpenBoth"
4241
Margin="0 0 4 0"
4342
ToolTip="{Loc nano-chat-edit}">
43+
<TextureRect StyleClasses="ButtonSquare"
44+
TexturePath="/Textures/Interface/VerbIcons/edit.svg.png"
45+
Stretch="KeepAspectCentered"
46+
MinSize="18 18" />
4447
</Button>
4548
<Button Name="DeleteChatButton"
4649
MaxSize="32 32"

Content.Client/DeltaV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml.cs

+11-8
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ public sealed partial class NanoChatUiFragment : BoxContainer
1818
{
1919
[Dependency] private readonly IGameTiming _timing = default!;
2020

21-
private const int MaxMessageLength = 256;
22-
2321
private readonly NewChatPopup _newChatPopup;
2422
private readonly EditChatPopup _editChatPopup;
2523
private uint? _currentChat;
@@ -50,8 +48,7 @@ private void SetupEventHandlers()
5048

5149
_editChatPopup.OnContactEdited += (number, name, job) =>
5250
{
53-
DeleteCurrentChat();
54-
ActionSendUiMessage?.Invoke(NanoChatUiMessageType.NewChat, number, name, job);
51+
ActionSendUiMessage?.Invoke(NanoChatUiMessageType.EditChat, number, name, job);
5552
};
5653

5754
NewChatButton.OnPressed += _ =>
@@ -71,18 +68,18 @@ private void SetupEventHandlers()
7168
{
7269
var length = args.Text.Length;
7370
var isValid = !string.IsNullOrWhiteSpace(args.Text) &&
74-
length <= MaxMessageLength &&
71+
length <= NanoChatMessage.MaxContentLength &&
7572
(_currentChat != null || _pendingChat != null);
7673

7774
SendButton.Disabled = !isValid;
7875

7976
// Show character count when over limit
80-
CharacterCount.Visible = length > MaxMessageLength;
81-
if (length > MaxMessageLength)
77+
CharacterCount.Visible = length > NanoChatMessage.MaxContentLength;
78+
if (length > NanoChatMessage.MaxContentLength)
8279
{
8380
CharacterCount.Text = Loc.GetString("nano-chat-message-too-long",
8481
("current", length),
85-
("max", MaxMessageLength));
82+
("max", NanoChatMessage.MaxContentLength));
8683
CharacterCount.StyleClasses.Add("LabelDanger");
8784
}
8885
};
@@ -100,6 +97,12 @@ private void SendMessage()
10097
return;
10198

10299
var messageContent = MessageInput.Text;
100+
if (!string.IsNullOrWhiteSpace(messageContent))
101+
{
102+
messageContent = messageContent.Trim();
103+
if (messageContent.Length > NanoChatMessage.MaxContentLength)
104+
messageContent = messageContent[..NanoChatMessage.MaxContentLength];
105+
}
103106

104107
// Add predicted message
105108
var predictedMessage = new NanoChatMessage(

Content.Client/DeltaV/CartridgeLoader/Cartridges/NewChatPopup.xaml.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq;
2+
using Content.Shared.Access.Components;
23
using Robust.Client.AutoGenerated;
34
using Robust.Client.UserInterface.CustomControls;
45
using Robust.Client.UserInterface.XAML;
@@ -8,7 +9,6 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges;
89
[GenerateTypedNameReferences]
910
public sealed partial class NewChatPopup : DefaultWindow
1011
{
11-
private const int MaxInputLength = 16;
1212
private const int MaxNumberLength = 4; // i hardcoded it to be 4 so suffer
1313

1414
public event Action<uint, string, string?>? OnChatCreated;
@@ -44,22 +44,23 @@ public NewChatPopup()
4444

4545
NameInput.OnTextChanged += args =>
4646
{
47-
if (args.Text.Length > MaxInputLength)
48-
NameInput.Text = args.Text[..MaxInputLength];
47+
if (args.Text.Length > IdCardConsoleComponent.MaxFullNameLength)
48+
NameInput.Text = args.Text[..IdCardConsoleComponent.MaxFullNameLength];
4949
ValidateInputs();
5050
};
5151

5252
JobInput.OnTextChanged += args =>
5353
{
54-
if (args.Text.Length > MaxInputLength)
55-
JobInput.Text = args.Text[..MaxInputLength];
54+
if (args.Text.Length > IdCardConsoleComponent.MaxJobTitleLength)
55+
JobInput.Text = args.Text[..IdCardConsoleComponent.MaxJobTitleLength];
5656
};
5757
}
5858

5959
private void ValidateInputs()
6060
{
6161
var isValid = !string.IsNullOrWhiteSpace(NumberInput.Text) &&
6262
!string.IsNullOrWhiteSpace(NameInput.Text) &&
63+
NumberInput.Text.Length == MaxNumberLength &&
6364
uint.TryParse(NumberInput.Text, out _);
6465

6566
CreateButton.Disabled = !isValid;

0 commit comments

Comments
 (0)