Admin notes (#7259)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<Control xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
MinWidth="400"
|
||||
MinHeight="400">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#25252A"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HorizontalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" Name="Notes" Access="Public" VerticalExpand="True"/>
|
||||
</ScrollContainer>
|
||||
<Label Name="NewNoteLabel" Text="{Loc admin-notes-new-note}" />
|
||||
<HistoryLineEdit Name="NewNote"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</Control>
|
||||
146
Content.Client/Administration/UI/Notes/AdminNotesControl.xaml.cs
Normal file
146
Content.Client/Administration/UI/Notes/AdminNotesControl.xaml.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using static Robust.Client.UserInterface.Controls.LineEdit;
|
||||
|
||||
namespace Content.Client.Administration.UI.Notes;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminNotesControl : Control
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||
|
||||
public event Action<int, string>? OnNoteChanged;
|
||||
public event Action<string>? OnNewNoteEntered;
|
||||
public event Action<int>? OnNoteDeleted;
|
||||
|
||||
private AdminNotesLinePopup? _popup;
|
||||
|
||||
public AdminNotesControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
NewNote.OnTextEntered += NewNoteEntered;
|
||||
}
|
||||
|
||||
private Dictionary<int, AdminNotesLine> Inputs { get; } = new();
|
||||
private bool CanCreate { get; set; }
|
||||
private bool CanDelete { get; set; }
|
||||
private bool CanEdit { get; set; }
|
||||
|
||||
private void NewNoteEntered(LineEditEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(args.Text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NewNote.Clear();
|
||||
OnNewNoteEntered?.Invoke(args.Text);
|
||||
}
|
||||
|
||||
private void NoteSubmitted(AdminNotesLine input)
|
||||
{
|
||||
var text = input.EditText.Trim();
|
||||
if (input.OriginalMessage == text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnNoteChanged?.Invoke(input.Id, text);
|
||||
}
|
||||
|
||||
private bool NoteRightClicked(AdminNotesLine line)
|
||||
{
|
||||
ClosePopup();
|
||||
|
||||
_popup = new AdminNotesLinePopup(line.Note, CanDelete, CanEdit);
|
||||
_popup.OnEditPressed += noteId =>
|
||||
{
|
||||
if (!Inputs.TryGetValue(noteId, out var input))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
input.SetEditable(true);
|
||||
};
|
||||
_popup.OnDeletePressed += noteId => OnNoteDeleted?.Invoke(noteId);
|
||||
|
||||
var box = UIBox2.FromDimensions(_ui.MousePositionScaled.Position, (1, 1));
|
||||
_popup.Open(box);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ClosePopup()
|
||||
{
|
||||
_popup?.Close();
|
||||
_popup = null;
|
||||
}
|
||||
|
||||
public void SetNotes(Dictionary<int, SharedAdminNote> notes)
|
||||
{
|
||||
foreach (var (id, input) in Inputs)
|
||||
{
|
||||
if (!notes.ContainsKey(id))
|
||||
{
|
||||
Notes.RemoveChild(input);
|
||||
Inputs.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var note in notes.Values.OrderBy(note => note.Id))
|
||||
{
|
||||
if (Inputs.TryGetValue(note.Id, out var input))
|
||||
{
|
||||
input.UpdateNote(note);
|
||||
continue;
|
||||
}
|
||||
|
||||
input = new AdminNotesLine(note);
|
||||
input.OnSubmitted += NoteSubmitted;
|
||||
input.OnRightClicked += NoteRightClicked;
|
||||
Notes.AddChild(input);
|
||||
Inputs[note.Id] = input;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPermissions(bool create, bool delete, bool edit)
|
||||
{
|
||||
CanCreate = create;
|
||||
CanDelete = delete;
|
||||
CanEdit = edit;
|
||||
NewNoteLabel.Visible = create;
|
||||
NewNote.Visible = create;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var input in Inputs.Values)
|
||||
{
|
||||
input.OnSubmitted -= NoteSubmitted;
|
||||
}
|
||||
|
||||
Inputs.Clear();
|
||||
NewNote.OnTextEntered -= NewNoteEntered;
|
||||
|
||||
if (_popup != null)
|
||||
{
|
||||
_ui.PopupRoot.RemoveChild(_popup);
|
||||
}
|
||||
|
||||
OnNoteChanged = null;
|
||||
OnNewNoteEntered = null;
|
||||
OnNoteDeleted = null;
|
||||
}
|
||||
}
|
||||
42
Content.Client/Administration/UI/Notes/AdminNotesEui.cs
Normal file
42
Content.Client/Administration/UI/Notes/AdminNotesEui.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Content.Shared.Eui;
|
||||
using JetBrains.Annotations;
|
||||
using static Content.Shared.Administration.Notes.AdminNoteEuiMsg;
|
||||
|
||||
namespace Content.Client.Administration.UI.Notes;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class AdminNotesEui : BaseEui
|
||||
{
|
||||
public AdminNotesEui()
|
||||
{
|
||||
NoteWindow = new AdminNotesWindow();
|
||||
NoteControl = NoteWindow.Notes;
|
||||
|
||||
NoteControl.OnNoteChanged += (id, text) => SendMessage(new EditNoteRequest(id, text));
|
||||
NoteControl.OnNewNoteEntered += text => SendMessage(new CreateNoteRequest(text));
|
||||
NoteControl.OnNoteDeleted += id => SendMessage(new DeleteNoteRequest(id));
|
||||
}
|
||||
|
||||
private AdminNotesWindow NoteWindow { get; }
|
||||
|
||||
private AdminNotesControl NoteControl { get; }
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if (state is not AdminNotesEuiState s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NoteWindow.SetTitlePlayer(s.NotedPlayerName);
|
||||
NoteControl.SetNotes(s.Notes);
|
||||
NoteControl.SetPermissions(s.CanCreate, s.CanDelete, s.CanEdit);
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
NoteWindow.OpenCentered();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Orientation="Vertical">
|
||||
<cc:HSeparator Name="Separator"/>
|
||||
</BoxContainer>
|
||||
142
Content.Client/Administration/UI/Notes/AdminNotesLine.xaml.cs
Normal file
142
Content.Client/Administration/UI/Notes/AdminNotesLine.xaml.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Input;
|
||||
using static Robust.Client.UserInterface.Controls.LineEdit;
|
||||
|
||||
namespace Content.Client.Administration.UI.Notes;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminNotesLine : BoxContainer
|
||||
{
|
||||
private RichTextLabel? _label;
|
||||
private LineEdit? _edit;
|
||||
|
||||
public AdminNotesLine(SharedAdminNote note)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Note = note;
|
||||
MouseFilter = MouseFilterMode.Pass;
|
||||
|
||||
AddLabel();
|
||||
}
|
||||
|
||||
public SharedAdminNote Note { get; private set; }
|
||||
public int Id => Note.Id;
|
||||
public string OriginalMessage => Note.Message;
|
||||
public string EditText => _edit?.Text ?? OriginalMessage;
|
||||
|
||||
public event Action<AdminNotesLine>? OnSubmitted;
|
||||
public event Func<AdminNotesLine, bool>? OnRightClicked;
|
||||
|
||||
private void AddLabel()
|
||||
{
|
||||
if (_edit != null)
|
||||
{
|
||||
_edit.OnTextEntered -= Submitted;
|
||||
_edit.OnFocusExit -= Submitted;
|
||||
|
||||
RemoveChild(_edit);
|
||||
_edit = null;
|
||||
}
|
||||
|
||||
_label = new RichTextLabel();
|
||||
_label.SetMessage(Note.Message);
|
||||
|
||||
AddChild(_label);
|
||||
_label.SetPositionFirst();
|
||||
|
||||
Separator.Visible = true;
|
||||
}
|
||||
|
||||
private void AddLineEdit()
|
||||
{
|
||||
if (_label != null)
|
||||
{
|
||||
RemoveChild(_label);
|
||||
_label = null;
|
||||
}
|
||||
|
||||
_edit = new LineEdit {Text = Note.Message};
|
||||
_edit.OnTextEntered += Submitted;
|
||||
_edit.OnFocusExit += Submitted;
|
||||
|
||||
AddChild(_edit);
|
||||
_edit.SetPositionFirst();
|
||||
_edit.GrabKeyboardFocus();
|
||||
_edit.CursorPosition = _edit.Text.Length;
|
||||
|
||||
Separator.Visible = false;
|
||||
}
|
||||
|
||||
private void Submitted(LineEditEventArgs args)
|
||||
{
|
||||
OnSubmitted?.Invoke(this);
|
||||
|
||||
AddLabel();
|
||||
|
||||
var note = Note with {Message = args.Text};
|
||||
UpdateNote(note);
|
||||
}
|
||||
|
||||
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindDown(args);
|
||||
|
||||
if (args.Function != EngineKeyFunctions.UIRightClick &&
|
||||
args.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (OnRightClicked?.Invoke(this) == true)
|
||||
{
|
||||
args.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateNote(SharedAdminNote note)
|
||||
{
|
||||
Note = note;
|
||||
_label?.SetMessage(note.Message);
|
||||
|
||||
if (_edit != null && _edit.Text != note.Message)
|
||||
{
|
||||
_edit.Text = note.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEditable(bool editable)
|
||||
{
|
||||
if (editable)
|
||||
{
|
||||
AddLineEdit();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLabel();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_edit != null)
|
||||
{
|
||||
_edit.OnTextEntered -= Submitted;
|
||||
_edit.OnFocusExit -= Submitted;
|
||||
}
|
||||
|
||||
OnSubmitted = null;
|
||||
OnRightClicked = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Popup xmlns="https://spacestation14.io"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#25252A"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="IdLabel"/>
|
||||
<Label Name="RoundIdLabel"/>
|
||||
<Label Name="CreatedByLabel"/>
|
||||
<Label Name="CreatedAtLabel"/>
|
||||
<Label Name="EditedByLabel"/>
|
||||
<Label Name="EditedAtLabel"/>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="EditButton" Text="{Loc admin-notes-edit}"/>
|
||||
<Control HorizontalExpand="True"/>
|
||||
<Button Name="DeleteButton" Text="{Loc admin-notes-delete}" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</Popup>
|
||||
@@ -0,0 +1,78 @@
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
namespace Content.Client.Administration.UI.Notes;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminNotesLinePopup : Popup
|
||||
{
|
||||
public event Action<int>? OnEditPressed;
|
||||
public event Action<int>? OnDeletePressed;
|
||||
|
||||
public AdminNotesLinePopup(SharedAdminNote note, bool showDelete, bool showEdit)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
NoteId = note.Id;
|
||||
DeleteButton.Visible = showDelete;
|
||||
EditButton.Visible = showEdit;
|
||||
|
||||
UserInterfaceManager.ModalRoot.AddChild(this);
|
||||
|
||||
IdLabel.Text = Loc.GetString("admin-notes-id", ("id", note.Id));
|
||||
RoundIdLabel.Text = note.Round == null
|
||||
? Loc.GetString("admin-notes-round-id-unknown")
|
||||
: Loc.GetString("admin-notes-round-id", ("id", note.Round));
|
||||
CreatedByLabel.Text = Loc.GetString("admin-notes-created-by", ("author", note.CreatedByName));
|
||||
CreatedAtLabel.Text = Loc.GetString("admin-notes-created-at", ("date", note.CreatedAt.ToString("dd MMM yyyy HH:mm:ss")));
|
||||
EditedByLabel.Text = Loc.GetString("admin-notes-last-edited-by", ("author", note.EditedByName));
|
||||
EditedAtLabel.Text = Loc.GetString("admin-notes-last-edited-at", ("date", note.LastEditedAt.ToString("dd MMM yyyy HH:mm:ss")));
|
||||
|
||||
EditButton.OnPressed += EditPressed;
|
||||
DeleteButton.OnPressed += DeletePressed;
|
||||
}
|
||||
|
||||
private int NoteId { get; }
|
||||
private bool ConfirmingDelete { get; set; }
|
||||
|
||||
private void EditPressed(ButtonEventArgs args)
|
||||
{
|
||||
OnEditPressed?.Invoke(NoteId);
|
||||
Close();
|
||||
}
|
||||
|
||||
private void DeletePressed(ButtonEventArgs args)
|
||||
{
|
||||
if (!ConfirmingDelete)
|
||||
{
|
||||
ConfirmingDelete = true;
|
||||
DeleteButton.Text = Loc.GetString("admin-notes-delete-confirm");
|
||||
DeleteButton.ModulateSelfOverride = Color.Red;
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmingDelete = false;
|
||||
DeleteButton.ModulateSelfOverride = null;
|
||||
OnDeletePressed?.Invoke(NoteId);
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditButton.OnPressed -= EditPressed;
|
||||
DeleteButton.OnPressed -= DeletePressed;
|
||||
|
||||
OnEditPressed = null;
|
||||
OnDeletePressed = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:notes="clr-namespace:Content.Client.Administration.UI.Notes"
|
||||
MinWidth="400"
|
||||
MinHeight="400">
|
||||
<notes:AdminNotesControl Name="Notes" Access="Public"/>
|
||||
</DefaultWindow>
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Administration.UI.Notes;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminNotesWindow : DefaultWindow
|
||||
{
|
||||
public AdminNotesWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void SetTitlePlayer(string playerName)
|
||||
{
|
||||
Title = Loc.GetString("admin-notes-title", ("player", playerName));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user