diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 9b274403e3..acd16b0b23 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -40,6 +40,12 @@ namespace Content.Client.Input
common.AddFunction(ContentKeyFunctions.ResetZoom);
common.AddFunction(ContentKeyFunctions.InspectEntity);
common.AddFunction(ContentKeyFunctions.ToggleRoundEndSummaryWindow);
+ // DeltaV - Begin NanoChat keybinds
+ common.AddFunction(ContentKeyFunctions.NanoChatNavigateUp);
+ common.AddFunction(ContentKeyFunctions.NanoChatNavigateDown);
+ common.AddFunction(ContentKeyFunctions.NanoChatNavigateUpUnread);
+ common.AddFunction(ContentKeyFunctions.NanoChatNavigateDownUnread);
+ // DeltaV - End NanoChat keybinds
// Not in engine, because engine cannot check for sanbox/admin status before starting placement.
common.AddFunction(ContentKeyFunctions.EditorCopyObject);
diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
index 17a52b3c5d..5a8fe55dc9 100644
--- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
@@ -240,6 +240,14 @@ namespace Content.Client.Options.UI.Tabs
AddButton(EngineKeyFunctions.EscapeMenu);
AddButton(ContentKeyFunctions.EscapeContext);
+ // DeltaV - Begin NanoChat keybinds
+ AddHeader("ui-options-header-nano-chat");
+ AddButton(ContentKeyFunctions.NanoChatNavigateUp);
+ AddButton(ContentKeyFunctions.NanoChatNavigateDown);
+ AddButton(ContentKeyFunctions.NanoChatNavigateUpUnread);
+ AddButton(ContentKeyFunctions.NanoChatNavigateDownUnread);
+ // DeltaV - End NanoChat keybinds
+
// Shitmed Change Start - TODO: Add hands, feet and groin targeting.
AddHeader("ui-options-header-targeting");
AddButton(ContentKeyFunctions.TargetHead);
diff --git a/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml b/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml
new file mode 100644
index 0000000000..f34eb2ce25
--- /dev/null
+++ b/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml.cs b/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml.cs
new file mode 100644
index 0000000000..e35aa989be
--- /dev/null
+++ b/Content.Client/_DV/CartridgeLoader/Cartridges/EditChatPopup.xaml.cs
@@ -0,0 +1,104 @@
+using Content.Shared.Access.Components;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client._DV.CartridgeLoader.Cartridges;
+
+[GenerateTypedNameReferences]
+public sealed partial class EditChatPopup : DefaultWindow
+{
+ private const int MaxNumberLength = 4;
+
+ // Used to see if the user input is different from the original data
+ // to check if the user can submit
+ private string _originalNumber = "";
+ private string _originalName = "";
+ private string _originalJob = "";
+
+ public event Action? OnContactEdited;
+
+ public EditChatPopup()
+ {
+ RobustXamlLoader.Load(this);
+
+ // margins trolling
+ ContentsContainer.Margin = new Thickness(3);
+
+ // Button handlers
+ CancelButton.OnPressed += _ => Close();
+ ConfirmButton.OnPressed += _ => EditChat();
+
+ NameInput.OnTabComplete += _ => JobInput.GrabKeyboardFocus();
+ NameInput.OnTextEntered += _ => EditChat();
+
+ JobInput.OnTabComplete += _ => NameInput.GrabKeyboardFocus();
+ JobInput.OnTextEntered += _ => EditChat();
+
+ // Input validation
+ NameInput.OnTextChanged += args =>
+ {
+ if (args.Text.Length > IdCardConsoleComponent.MaxFullNameLength)
+ NameInput.Text = args.Text[..IdCardConsoleComponent.MaxFullNameLength];
+ ValidateInputs();
+ };
+
+ JobInput.OnTextChanged += args =>
+ {
+ if (args.Text.Length > IdCardConsoleComponent.MaxJobTitleLength)
+ JobInput.Text = args.Text[..IdCardConsoleComponent.MaxJobTitleLength];
+ ValidateInputs();
+ };
+ }
+
+ private void ValidateInputs()
+ {
+ var isValid = !string.IsNullOrWhiteSpace(NumberInput.Text) &&
+ !string.IsNullOrWhiteSpace(NameInput.Text) &&
+ NumberInput.Text.Length == MaxNumberLength &&
+ uint.TryParse(NumberInput.Text, out _) &&
+ // Only valid if there are any changes
+ (NumberInput.Text != _originalNumber ||
+ NameInput.Text != _originalName ||
+ JobInput.Text != _originalJob);
+
+ ConfirmButton.Disabled = !isValid;
+ }
+
+ private void EditChat()
+ {
+ if (!uint.TryParse(NumberInput.Text, out var number))
+ return;
+
+ var name = NameInput.Text.Trim();
+ var job = string.IsNullOrWhiteSpace(JobInput.Text) ? null : JobInput.Text.Trim();
+
+ OnContactEdited?.Invoke(number, name, job);
+ Close();
+ }
+
+ public void ClearInputs()
+ {
+ NameInput.Text = string.Empty;
+ JobInput.Text = string.Empty;
+ ValidateInputs();
+ }
+
+ public void SetNumberInput(string newNumber)
+ {
+ NumberInput.Text = newNumber.PadLeft(MaxNumberLength, '0');
+ _originalNumber = newNumber;
+ }
+
+ public void SetNameInput(string newName)
+ {
+ NameInput.Text = newName;
+ _originalName = newName;
+ }
+
+ public void SetJobInput(string newJob)
+ {
+ JobInput.Text = newJob;
+ _originalJob = newJob;
+ }
+}
diff --git a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatEntry.xaml.cs b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatEntry.xaml.cs
index 95f2eba283..ed870fa29e 100644
--- a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatEntry.xaml.cs
+++ b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatEntry.xaml.cs
@@ -1,4 +1,6 @@
using Content.Shared._DV.CartridgeLoader.Cartridges;
+using Content.Shared._DV.NanoChat;
+using Content.Shared.Access.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -29,8 +31,8 @@ public sealed partial class NanoChatEntry : BoxContainer
_pressHandler = _ => OnPressed?.Invoke(_number);
ChatButton.OnPressed += _pressHandler;
- NameLabel.Text = recipient.Name;
- JobLabel.Text = recipient.JobTitle ?? "";
+ NameLabel.Text = SharedNanoChatSystem.Truncate(recipient.Name, IdCardConsoleComponent.MaxFullNameLength);
+ JobLabel.Text = SharedNanoChatSystem.Truncate(recipient.JobTitle ?? "", IdCardConsoleComponent.MaxJobTitleLength);
JobLabel.Visible = !string.IsNullOrEmpty(recipient.JobTitle);
UnreadIndicator.Visible = recipient.HasUnread;
diff --git a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatLookupView.xaml.cs b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatLookupView.xaml.cs
index c143e373d6..fb1b56aa41 100644
--- a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatLookupView.xaml.cs
+++ b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatLookupView.xaml.cs
@@ -1,6 +1,7 @@
using System.Numerics;
using Content.Shared._DV.CartridgeLoader.Cartridges;
using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -28,6 +29,19 @@ public sealed partial class NanoChatLookupView : PanelContainer
for (var idx = 0; idx < contacts.Count; idx++)
{
var contact = contacts[idx];
+ var isEvenRow = idx % 2 == 0;
+ var contactControl = new ContactContainer(contact, state, isEvenRow, OnStartChat);
+ ContactsList.AddChild(contactControl);
+ }
+ }
+
+ public sealed class ContactContainer : PanelContainer
+ {
+ public ContactContainer(NanoChatRecipient contact, NanoChatUiState state, bool isEvenRow, Action? onStartChat)
+ {
+ HorizontalExpand = true;
+ StyleClasses.Add(isEvenRow ? "PanelBackgroundBaseDark" : "PanelBackgroundLight");
+
var nameLabel = new Label()
{
Text = contact.Name,
@@ -36,7 +50,7 @@ public sealed partial class NanoChatLookupView : PanelContainer
};
var numberLabel = new Label()
{
- Text = $"#{contacts[idx].Number:D4}",
+ Text = $"#{contact.Number:D4}",
HorizontalAlignment = HAlignment.Right,
Margin = new Thickness(0, 0, 36, 0),
};
@@ -49,25 +63,17 @@ public sealed partial class NanoChatLookupView : PanelContainer
ToolTip = Loc.GetString("nano-chat-new-chat"),
};
startChatButton.AddStyleClass("OpenBoth");
+
if (contact.Number == state.OwnNumber || state.Recipients.ContainsKey(contact.Number) || state.MaxRecipients <= state.Recipients.Count)
{
startChatButton.Disabled = true;
}
- startChatButton.OnPressed += _ => OnStartChat?.Invoke(contact);
- var panel = new PanelContainer()
- {
- HorizontalExpand = true,
- };
+ startChatButton.OnPressed += _ => onStartChat?.Invoke(contact);
- panel.AddChild(nameLabel);
- panel.AddChild(numberLabel);
- panel.AddChild(startChatButton);
-
- var styleClass = idx % 2 == 0 ? "PanelBackgroundBaseDark" : "PanelBackgroundLight";
- panel.StyleClasses.Add(styleClass);
-
- ContactsList.AddChild(panel);
+ AddChild(nameLabel);
+ AddChild(numberLabel);
+ AddChild(startChatButton);
}
}
}
diff --git a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml
index 9808cdbddb..a8014a1ebf 100644
--- a/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml
+++ b/Content.Client/_DV/CartridgeLoader/Cartridges/NanoChatUiFragment.xaml
@@ -34,17 +34,6 @@
StyleClasses="LabelSubText"
VerticalAlignment="Center"
Margin="0 0 8 0" />
-