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:
@@ -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,8 +83,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
|
|
||||||
RecordListing.OnItemDeselected += _ =>
|
RecordListing.OnItemDeselected += _ =>
|
||||||
{
|
{
|
||||||
if (!_isPopulating)
|
OnKeySelected?.Invoke(null);
|
||||||
OnKeySelected?.Invoke(null);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterType.OnItemSelected += eventArgs =>
|
FilterType.OnItemSelected += eventArgs =>
|
||||||
@@ -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)
|
||||||
@@ -211,10 +246,7 @@ 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user