Admin notes (#7259)

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
DrSmugleaf
2022-04-16 20:57:50 +02:00
committed by GitHub
parent 0041b9d933
commit 5227d1a023
38 changed files with 4009 additions and 23 deletions

View File

@@ -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>

View 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;
}
}

View 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();
}
}

View File

@@ -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>

View 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;
}
}

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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));
}
}