Improve Criminal Records Computer usability (#30292)

* Avoid destroying and recreating record list on every update message

* Add early-out on nullptr input

* Remove sussy null suppress

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
eoineoineoin
2024-08-09 08:41:29 +01:00
committed by GitHub
parent 0b2fa941a7
commit d0a2187a9b

View File

@@ -7,10 +7,12 @@ using Content.Shared.Security;
using Content.Shared.StationRecords; using Content.Shared.StationRecords;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using System.Linq;
namespace Content.Client.CriminalRecords; namespace Content.Client.CriminalRecords;
@@ -36,7 +38,6 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
public Action<SecurityStatus, string>? OnDialogConfirmed; public Action<SecurityStatus, string>? OnDialogConfirmed;
private uint _maxLength; private uint _maxLength;
private bool _isPopulating;
private bool _access; private bool _access;
private uint? _selectedKey; private uint? _selectedKey;
private CriminalRecord? _selectedRecord; private CriminalRecord? _selectedRecord;
@@ -74,7 +75,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
RecordListing.OnItemSelected += args => RecordListing.OnItemSelected += args =>
{ {
if (_isPopulating || RecordListing[args.ItemIndex].Metadata is not uint cast) if (RecordListing[args.ItemIndex].Metadata is not uint cast)
return; return;
OnKeySelected?.Invoke(cast); OnKeySelected?.Invoke(cast);
@@ -82,7 +83,6 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
RecordListing.OnItemDeselected += _ => RecordListing.OnItemDeselected += _ =>
{ {
if (!_isPopulating)
OnKeySelected?.Invoke(null); OnKeySelected?.Invoke(null);
}; };
@@ -133,13 +133,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
FilterType.SelectId((int)_currentFilterType); FilterType.SelectId((int)_currentFilterType);
// set up the records listing panel NoRecords.Visible = state.RecordListing == null || state.RecordListing.Count == 0;
RecordListing.Clear(); PopulateRecordListing(state.RecordListing);
var hasRecords = state.RecordListing != null && state.RecordListing.Count > 0;
NoRecords.Visible = !hasRecords;
if (hasRecords)
PopulateRecordListing(state.RecordListing!);
// set up the selected person's record // set up the selected person's record
var selected = _selectedKey != null; var selected = _selectedKey != null;
@@ -167,19 +162,59 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
} }
} }
private void PopulateRecordListing(Dictionary<uint, string> listing) private void PopulateRecordListing(Dictionary<uint, string>? listing)
{ {
_isPopulating = true; if (listing == null)
foreach (var (key, name) in listing)
{ {
var item = RecordListing.AddItem(name); RecordListing.Clear();
item.Metadata = key; return;
item.Selected = key == _selectedKey;
} }
_isPopulating = false;
RecordListing.SortItemsByText(); var entries = listing.ToList();
entries.Sort((a, b) => string.Compare(a.Value, b.Value, StringComparison.Ordinal));
// `entries` now contains the definitive list of items which should be in
// our list of records and is in the order we want to present those items.
// Walk through the existing items in RecordListing and in the updated listing
// in parallel to synchronize the items in RecordListing with `entries`.
int i = RecordListing.Count - 1;
int j = entries.Count - 1;
while(i >= 0 && j >= 0)
{
var strcmp = string.Compare(RecordListing[i].Text, entries[j].Value, StringComparison.Ordinal);
if (strcmp == 0)
{
// This item exists in both RecordListing and `entries`. Nothing to do.
i--;
j--;
}
else if (strcmp > 0)
{
// Item exists in RecordListing, but not in `entries`. Remove it.
RecordListing.RemoveAt(i);
i--;
}
else if (strcmp < 0)
{
// A new entry which doesn't exist in RecordListing. Create it.
RecordListing.Insert(i + 1, new ItemList.Item(RecordListing){Text = entries[j].Value, Metadata = entries[j].Key});
j--;
}
}
// Any remaining items in RecordListing don't exist in `entries`, so remove them
while (i >= 0)
{
RecordListing.RemoveAt(i);
i--;
}
// And finally, any remaining items in `entries`, don't exist in RecordListing. Create them.
while (j >= 0)
{
RecordListing.Insert(0, new ItemList.Item(RecordListing){Text = entries[j].Value, Metadata = entries[j].Key});
j--;
}
} }
private void PopulateRecordContainer(GeneralStationRecord stationRecord, CriminalRecord criminalRecord) private void PopulateRecordContainer(GeneralStationRecord stationRecord, CriminalRecord criminalRecord)
@@ -210,12 +245,9 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
} }
private void FilterListingOfRecords(string text = "") private void FilterListingOfRecords(string text = "")
{
if (!_isPopulating)
{ {
OnFiltersChanged?.Invoke(_currentFilterType, text); OnFiltersChanged?.Invoke(_currentFilterType, text);
} }
}
private void SetStatus(SecurityStatus status) private void SetStatus(SecurityStatus status)
{ {