Criminal Records Computer Better UX + Filtering (#32352)
* First pass at new Criminal Records Computer need buttons to highlight. * Filter status tabs/buttons now activate correctly via UpdateState * Removed unneeded Directives * Fix typo + undo VSCode changes * Implement Emo Feedback Loc NA and use inject deps Cannot use inject deps on sprite system. * try to undo vscode launch.json change * Added requests + Filter dropdown list + jobs Fixed maintainer fix requests, Added Job to announcement channel output Removed toggle buttons in-place of a dropdown list * Fixed missed merge conflict + fixed an bug with filterstatus not showing on re-open ui * Update criminal-records.ftl Fixed lint error. whoops. * Update Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs typo Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com> * impliment chromiumboy feedback hopefully this will do it.... --------- Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
This commit is contained in:
@@ -39,6 +39,8 @@ public sealed class CriminalRecordsConsoleBoundUserInterface : BoundUserInterfac
|
|||||||
SendMessage(new CriminalRecordChangeStatus(status, null));
|
SendMessage(new CriminalRecordChangeStatus(status, null));
|
||||||
_window.OnDialogConfirmed += (status, reason) =>
|
_window.OnDialogConfirmed += (status, reason) =>
|
||||||
SendMessage(new CriminalRecordChangeStatus(status, reason));
|
SendMessage(new CriminalRecordChangeStatus(status, reason));
|
||||||
|
_window.OnStatusFilterPressed += (statusFilter) =>
|
||||||
|
SendMessage(new CriminalRecordSetStatusFilter(statusFilter));
|
||||||
_window.OnHistoryUpdated += UpdateHistory;
|
_window.OnHistoryUpdated += UpdateHistory;
|
||||||
_window.OnHistoryClosed += () => _historyWindow?.Close();
|
_window.OnHistoryClosed += () => _historyWindow?.Close();
|
||||||
_window.OnClose += Close;
|
_window.OnClose += Close;
|
||||||
|
|||||||
@@ -1,36 +1,142 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'criminal-records-console-window-title'}"
|
Title="{Loc 'criminal-records-console-window-title'}"
|
||||||
MinSize="660 400">
|
MinSize="695 440">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<!-- Record search bar
|
<BoxContainer Name="AllList"
|
||||||
TODO: make this into a control shared with general records -->
|
Orientation="Vertical"
|
||||||
<BoxContainer Margin="5 5 5 10" HorizontalExpand="true" VerticalAlignment="Center">
|
VerticalExpand="True"
|
||||||
<OptionButton Name="FilterType" MinWidth="200" Margin="0 0 10 0"/> <!-- Populated in constructor -->
|
HorizontalExpand="True"
|
||||||
<LineEdit Name="FilterText" PlaceHolder="{Loc 'criminal-records-filter-placeholder'}" HorizontalExpand="True"/>
|
Margin="8">
|
||||||
</BoxContainer>
|
<!-- Record search bar -->
|
||||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
|
<BoxContainer Margin="5 5 5 10"
|
||||||
<!-- Record listing -->
|
HorizontalExpand="true"
|
||||||
<BoxContainer Orientation="Vertical" Margin="5" MinWidth="250" MaxWidth="250">
|
VerticalAlignment="Center">
|
||||||
<Label Name="RecordListingTitle" Text="{Loc 'criminal-records-console-records-list-title'}" HorizontalExpand="True" Align="Center"/>
|
<OptionButton Name="FilterType"
|
||||||
<Label Name="NoRecords" Text="{Loc 'criminal-records-console-no-records'}" HorizontalExpand="True" Align="Center" FontColorOverride="DarkGray"/>
|
MinWidth="250"
|
||||||
<ScrollContainer VerticalExpand="True">
|
Margin="0 0 10 0" />
|
||||||
<ItemList Name="RecordListing"/> <!-- Populated when loading state -->
|
<!-- Populated in constructor -->
|
||||||
</ScrollContainer>
|
<LineEdit Name="FilterText"
|
||||||
|
PlaceHolder="{Loc 'criminal-records-filter-placeholder'}"
|
||||||
|
HorizontalExpand="True" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Label Name="RecordUnselected" Text="{Loc 'criminal-records-console-select-record-info'}" HorizontalExpand="True" Align="Center" FontColorOverride="DarkGray"/>
|
<BoxContainer Orientation="Horizontal"
|
||||||
<!-- Selected record info -->
|
VerticalExpand="True">
|
||||||
<BoxContainer Name="PersonContainer" Orientation="Vertical" Margin="5" Visible="False">
|
<!-- Record listing -->
|
||||||
<Label Name="PersonName" StyleClasses="LabelBig"/>
|
<BoxContainer Orientation="Vertical"
|
||||||
<Label Name="PersonPrints"/>
|
Margin="10 10"
|
||||||
<Label Name="PersonDna"/>
|
MinWidth="250"
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5" />
|
MaxWidth="250">
|
||||||
<BoxContainer Orientation="Horizontal" Margin="5 5 5 5">
|
<Label Name="RecordListingTitle"
|
||||||
<Label Name="StatusLabel" Text="{Loc 'criminal-records-console-status'}" FontColorOverride="DarkGray"/>
|
Text="{Loc 'criminal-records-console-records-list-title'}"
|
||||||
<OptionButton Name="StatusOptionButton"/> <!-- Populated in constructor -->
|
HorizontalExpand="True"
|
||||||
|
Align="Center" />
|
||||||
|
<Label Name="NoRecords"
|
||||||
|
Text="{Loc 'criminal-records-console-no-records'}"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Align="Center"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<ScrollContainer VerticalExpand="True">
|
||||||
|
<ItemList Name="RecordListing" />
|
||||||
|
<!-- Populated when loading state -->
|
||||||
|
</ScrollContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<RichTextLabel Name="WantedReason" Visible="False"/>
|
<Label Name="RecordUnselected"
|
||||||
<Button Name="HistoryButton" Text="{Loc 'criminal-records-console-crime-history'}"/>
|
Text="{Loc 'criminal-records-console-select-record-info'}"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Align="Center"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<!-- Selected record info -->
|
||||||
|
<BoxContainer Name="PersonContainer"
|
||||||
|
Orientation="Vertical"
|
||||||
|
VerticalExpand="True"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Margin="5"
|
||||||
|
Visible="False">
|
||||||
|
<Label Name="PersonName"
|
||||||
|
Margin="0 0 0 5"
|
||||||
|
StyleClasses="LabelBig" />
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="0 0 0 5">
|
||||||
|
<Label Text="{Loc 'crew-monitoring-user-interface-job'}:"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Text=":"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<TextureRect Name="PersonJobIcon"
|
||||||
|
TextureScale="2 2"
|
||||||
|
Margin="6 0"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<Label Name="PersonJob" />
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="0 0 0 5">
|
||||||
|
<Label Text="{Loc 'general-station-record-prints-filter'}"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Text=":"
|
||||||
|
Margin="0 0 6 0"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Name="PersonPrints" />
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="0 0 0 5">
|
||||||
|
<Label Text="{Loc 'general-station-record-dna-filter'}"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Text=":"
|
||||||
|
Margin="0 0 6 0"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Name="PersonDna" />
|
||||||
|
</BoxContainer>
|
||||||
|
<PanelContainer StyleClasses="LowDivider"
|
||||||
|
Margin="0 5 0 5" />
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="0 5 0 5">
|
||||||
|
<Label Name="StatusLabel"
|
||||||
|
Text="{Loc 'criminal-records-console-status'}"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Text=":"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<Label Name="PersonStatus"
|
||||||
|
FontColorOverride="DarkGray" />
|
||||||
|
<AnimatedTextureRect Name="PersonStatusTX"
|
||||||
|
Margin="8 0" />
|
||||||
|
<OptionButton Name="StatusOptionButton"
|
||||||
|
MinWidth="130" />
|
||||||
|
<!-- Populated in constructor -->
|
||||||
|
</BoxContainer>
|
||||||
|
<RichTextLabel Name="WantedReason"
|
||||||
|
Visible="False"
|
||||||
|
MaxWidth="425" />
|
||||||
|
<Button Name="HistoryButton"
|
||||||
|
Text="{Loc 'criminal-records-console-crime-history'}"
|
||||||
|
Margin="0 5" />
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="0 0 0 5">
|
||||||
|
<OptionButton
|
||||||
|
Name="CrewListFilter"
|
||||||
|
MinWidth="250"
|
||||||
|
Margin="10 0 10 0" />
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
<!-- Footer -->
|
||||||
|
<BoxContainer Orientation="Vertical">
|
||||||
|
<PanelContainer StyleClasses="LowDivider" />
|
||||||
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
Margin="10 2 5 0"
|
||||||
|
VerticalAlignment="Bottom">
|
||||||
|
<Label Text="{Loc 'criminal-records-console-flavor-left'}"
|
||||||
|
StyleClasses="WindowFooterText" />
|
||||||
|
<Label Text="{Loc 'criminal-records-console-flavor-right'}"
|
||||||
|
StyleClasses="WindowFooterText"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Margin="0 0 5 0" />
|
||||||
|
<TextureRect StyleClasses="NTLogoDark"
|
||||||
|
Stretch="KeepAspectCentered"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
SetSize="19 19" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using Content.Shared.StatusIcon;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.CriminalRecords;
|
namespace Content.Client.CriminalRecords;
|
||||||
|
|
||||||
@@ -24,6 +27,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
private readonly IPrototypeManager _proto;
|
private readonly IPrototypeManager _proto;
|
||||||
private readonly IRobustRandom _random;
|
private readonly IRobustRandom _random;
|
||||||
private readonly AccessReaderSystem _accessReader;
|
private readonly AccessReaderSystem _accessReader;
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
private readonly SpriteSystem _spriteSystem;
|
||||||
|
|
||||||
public readonly EntityUid Console;
|
public readonly EntityUid Console;
|
||||||
|
|
||||||
@@ -33,10 +38,12 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
public Action<uint?>? OnKeySelected;
|
public Action<uint?>? OnKeySelected;
|
||||||
public Action<StationRecordFilterType, string>? OnFiltersChanged;
|
public Action<StationRecordFilterType, string>? OnFiltersChanged;
|
||||||
public Action<SecurityStatus>? OnStatusSelected;
|
public Action<SecurityStatus>? OnStatusSelected;
|
||||||
|
public Action<uint>? OnCheckStatus;
|
||||||
public Action<CriminalRecord, bool, bool>? OnHistoryUpdated;
|
public Action<CriminalRecord, bool, bool>? OnHistoryUpdated;
|
||||||
public Action? OnHistoryClosed;
|
public Action? OnHistoryClosed;
|
||||||
public Action<SecurityStatus, string>? OnDialogConfirmed;
|
public Action<SecurityStatus, string>? OnDialogConfirmed;
|
||||||
|
|
||||||
|
public Action<SecurityStatus>? OnStatusFilterPressed;
|
||||||
private uint _maxLength;
|
private uint _maxLength;
|
||||||
private bool _access;
|
private bool _access;
|
||||||
private uint? _selectedKey;
|
private uint? _selectedKey;
|
||||||
@@ -46,6 +53,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
|
|
||||||
private StationRecordFilterType _currentFilterType;
|
private StationRecordFilterType _currentFilterType;
|
||||||
|
|
||||||
|
private SecurityStatus _currentCrewListFilter;
|
||||||
|
|
||||||
public CriminalRecordsConsoleWindow(EntityUid console, uint maxLength, IPlayerManager playerManager, IPrototypeManager prototypeManager, IRobustRandom robustRandom, AccessReaderSystem accessReader)
|
public CriminalRecordsConsoleWindow(EntityUid console, uint maxLength, IPlayerManager playerManager, IPrototypeManager prototypeManager, IRobustRandom robustRandom, AccessReaderSystem accessReader)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
@@ -55,10 +64,14 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
_proto = prototypeManager;
|
_proto = prototypeManager;
|
||||||
_random = robustRandom;
|
_random = robustRandom;
|
||||||
_accessReader = accessReader;
|
_accessReader = accessReader;
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||||
|
|
||||||
_maxLength = maxLength;
|
_maxLength = maxLength;
|
||||||
_currentFilterType = StationRecordFilterType.Name;
|
_currentFilterType = StationRecordFilterType.Name;
|
||||||
|
|
||||||
|
_currentCrewListFilter = SecurityStatus.None;
|
||||||
|
|
||||||
OpenCentered();
|
OpenCentered();
|
||||||
|
|
||||||
foreach (var item in Enum.GetValues<StationRecordFilterType>())
|
foreach (var item in Enum.GetValues<StationRecordFilterType>())
|
||||||
@@ -71,6 +84,12 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
AddStatusSelect(status);
|
AddStatusSelect(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Populate status to filter crew list
|
||||||
|
foreach (var item in Enum.GetValues<SecurityStatus>())
|
||||||
|
{
|
||||||
|
CrewListFilter.AddItem(GetCrewListFilterLocals(item), (int)item);
|
||||||
|
}
|
||||||
|
|
||||||
OnClose += () => _reasonDialog?.Close();
|
OnClose += () => _reasonDialog?.Close();
|
||||||
|
|
||||||
RecordListing.OnItemSelected += args =>
|
RecordListing.OnItemSelected += args =>
|
||||||
@@ -97,6 +116,20 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Select Status to filter crew
|
||||||
|
CrewListFilter.OnItemSelected += eventArgs =>
|
||||||
|
{
|
||||||
|
var type = (SecurityStatus)eventArgs.Id;
|
||||||
|
|
||||||
|
if (_currentCrewListFilter != type)
|
||||||
|
{
|
||||||
|
_currentCrewListFilter = type;
|
||||||
|
|
||||||
|
StatusFilterPressed(type);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FilterText.OnTextEntered += args =>
|
FilterText.OnTextEntered += args =>
|
||||||
{
|
{
|
||||||
FilterListingOfRecords(args.Text);
|
FilterListingOfRecords(args.Text);
|
||||||
@@ -104,16 +137,21 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
|
|
||||||
StatusOptionButton.OnItemSelected += args =>
|
StatusOptionButton.OnItemSelected += args =>
|
||||||
{
|
{
|
||||||
SetStatus((SecurityStatus) args.Id);
|
SetStatus((SecurityStatus)args.Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
HistoryButton.OnPressed += _ =>
|
HistoryButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
if (_selectedRecord is {} record)
|
if (_selectedRecord is { } record)
|
||||||
OnHistoryUpdated?.Invoke(record, _access, true);
|
OnHistoryUpdated?.Invoke(record, _access, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StatusFilterPressed(SecurityStatus statusSelected)
|
||||||
|
{
|
||||||
|
OnStatusFilterPressed?.Invoke(statusSelected);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateState(CriminalRecordsConsoleState state)
|
public void UpdateState(CriminalRecordsConsoleState state)
|
||||||
{
|
{
|
||||||
if (state.Filter != null)
|
if (state.Filter != null)
|
||||||
@@ -129,10 +167,14 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.FilterStatus != _currentCrewListFilter)
|
||||||
|
{
|
||||||
|
_currentCrewListFilter = state.FilterStatus;
|
||||||
|
}
|
||||||
|
|
||||||
_selectedKey = state.SelectedKey;
|
_selectedKey = state.SelectedKey;
|
||||||
|
|
||||||
FilterType.SelectId((int)_currentFilterType);
|
FilterType.SelectId((int)_currentFilterType);
|
||||||
|
CrewListFilter.SelectId((int)_currentCrewListFilter);
|
||||||
NoRecords.Visible = state.RecordListing == null || state.RecordListing.Count == 0;
|
NoRecords.Visible = state.RecordListing == null || state.RecordListing.Count == 0;
|
||||||
PopulateRecordListing(state.RecordListing);
|
PopulateRecordListing(state.RecordListing);
|
||||||
|
|
||||||
@@ -179,7 +221,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
// in parallel to synchronize the items in RecordListing with `entries`.
|
// in parallel to synchronize the items in RecordListing with `entries`.
|
||||||
int i = RecordListing.Count - 1;
|
int i = RecordListing.Count - 1;
|
||||||
int j = entries.Count - 1;
|
int j = entries.Count - 1;
|
||||||
while(i >= 0 && j >= 0)
|
while (i >= 0 && j >= 0)
|
||||||
{
|
{
|
||||||
var strcmp = string.Compare(RecordListing[i].Text, entries[j].Value, StringComparison.Ordinal);
|
var strcmp = string.Compare(RecordListing[i].Text, entries[j].Value, StringComparison.Ordinal);
|
||||||
if (strcmp == 0)
|
if (strcmp == 0)
|
||||||
@@ -212,23 +254,44 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
// And finally, any remaining items in `entries`, don't exist in RecordListing. Create them.
|
// And finally, any remaining items in `entries`, don't exist in RecordListing. Create them.
|
||||||
while (j >= 0)
|
while (j >= 0)
|
||||||
{
|
{
|
||||||
RecordListing.Insert(0, new ItemList.Item(RecordListing){Text = entries[j].Value, Metadata = entries[j].Key});
|
RecordListing.Insert(0, new ItemList.Item(RecordListing){ Text = entries[j].Value, Metadata = entries[j].Key });
|
||||||
j--;
|
j--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateRecordContainer(GeneralStationRecord stationRecord, CriminalRecord criminalRecord)
|
private void PopulateRecordContainer(GeneralStationRecord stationRecord, CriminalRecord criminalRecord)
|
||||||
{
|
{
|
||||||
|
var specifier = new SpriteSpecifier.Rsi(new ResPath("Interface/Misc/job_icons.rsi"), "Unknown");
|
||||||
var na = Loc.GetString("generic-not-available-shorthand");
|
var na = Loc.GetString("generic-not-available-shorthand");
|
||||||
PersonName.Text = stationRecord.Name;
|
PersonName.Text = stationRecord.Name;
|
||||||
PersonPrints.Text = Loc.GetString("general-station-record-console-record-fingerprint", ("fingerprint", stationRecord.Fingerprint ?? na));
|
PersonJob.Text = stationRecord.JobTitle ?? na;
|
||||||
PersonDna.Text = Loc.GetString("general-station-record-console-record-dna", ("dna", stationRecord.DNA ?? na));
|
|
||||||
|
|
||||||
StatusOptionButton.SelectId((int) criminalRecord.Status);
|
// Job icon
|
||||||
if (criminalRecord.Reason is {} reason)
|
if (_proto.TryIndex<JobIconPrototype>(stationRecord.JobIcon, out var proto))
|
||||||
|
{
|
||||||
|
PersonJobIcon.Texture = _spriteSystem.Frame0(proto.Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
PersonPrints.Text = stationRecord.Fingerprint ?? Loc.GetString("generic-not-available-shorthand");
|
||||||
|
PersonDna.Text = stationRecord.DNA ?? Loc.GetString("generic-not-available-shorthand");
|
||||||
|
|
||||||
|
if (criminalRecord.Status != SecurityStatus.None)
|
||||||
|
{
|
||||||
|
specifier = new SpriteSpecifier.Rsi(new ResPath("Interface/Misc/security_icons.rsi"), GetStatusIcon(criminalRecord.Status));
|
||||||
|
}
|
||||||
|
PersonStatusTX.SetFromSpriteSpecifier(specifier);
|
||||||
|
PersonStatusTX.DisplayRect.TextureScale = new Vector2(3f, 3f);
|
||||||
|
|
||||||
|
StatusOptionButton.SelectId((int)criminalRecord.Status);
|
||||||
|
if (criminalRecord.Reason is { } reason)
|
||||||
{
|
{
|
||||||
var message = FormattedMessage.FromMarkupOrThrow(Loc.GetString("criminal-records-console-wanted-reason"));
|
var message = FormattedMessage.FromMarkupOrThrow(Loc.GetString("criminal-records-console-wanted-reason"));
|
||||||
|
|
||||||
|
if (criminalRecord.Status == SecurityStatus.Suspected)
|
||||||
|
{
|
||||||
|
message = FormattedMessage.FromMarkupOrThrow(Loc.GetString("criminal-records-console-suspected-reason"));
|
||||||
|
}
|
||||||
message.AddText($": {reason}");
|
message.AddText($": {reason}");
|
||||||
|
|
||||||
WantedReason.SetMessage(message);
|
WantedReason.SetMessage(message);
|
||||||
WantedReason.Visible = true;
|
WantedReason.Visible = true;
|
||||||
}
|
}
|
||||||
@@ -288,9 +351,37 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
|||||||
|
|
||||||
_reasonDialog.OnClose += () => { _reasonDialog = null; };
|
_reasonDialog.OnClose += () => { _reasonDialog = null; };
|
||||||
}
|
}
|
||||||
|
private string GetStatusIcon(SecurityStatus status)
|
||||||
|
{
|
||||||
|
return status switch
|
||||||
|
{
|
||||||
|
SecurityStatus.Paroled => "hud_paroled",
|
||||||
|
SecurityStatus.Wanted => "hud_wanted",
|
||||||
|
SecurityStatus.Detained => "hud_incarcerated",
|
||||||
|
SecurityStatus.Discharged => "hud_discharged",
|
||||||
|
SecurityStatus.Suspected => "hud_suspected",
|
||||||
|
_ => "SecurityIconNone"
|
||||||
|
};
|
||||||
|
}
|
||||||
private string GetTypeFilterLocals(StationRecordFilterType type)
|
private string GetTypeFilterLocals(StationRecordFilterType type)
|
||||||
{
|
{
|
||||||
return Loc.GetString($"criminal-records-{type.ToString().ToLower()}-filter");
|
return Loc.GetString($"criminal-records-{type.ToString().ToLower()}-filter");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetCrewListFilterLocals(SecurityStatus type)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
|
||||||
|
// If "NONE" override to "show all"
|
||||||
|
if (type == SecurityStatus.None)
|
||||||
|
{
|
||||||
|
result = Loc.GetString("criminal-records-console-show-all");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = Loc.GetString($"criminal-records-status-{type.ToString().ToLower()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ using Robust.Server.GameObjects;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Security.Components;
|
using Content.Shared.Security.Components;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.Roles.Jobs;
|
||||||
|
|
||||||
namespace Content.Server.CriminalRecords.Systems;
|
namespace Content.Server.CriminalRecords.Systems;
|
||||||
|
|
||||||
@@ -42,6 +44,7 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
subs.Event<CriminalRecordChangeStatus>(OnChangeStatus);
|
subs.Event<CriminalRecordChangeStatus>(OnChangeStatus);
|
||||||
subs.Event<CriminalRecordAddHistory>(OnAddHistory);
|
subs.Event<CriminalRecordAddHistory>(OnAddHistory);
|
||||||
subs.Event<CriminalRecordDeleteHistory>(OnDeleteHistory);
|
subs.Event<CriminalRecordDeleteHistory>(OnDeleteHistory);
|
||||||
|
subs.Event<CriminalRecordSetStatusFilter>(OnStatusFilterPressed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +60,11 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
ent.Comp.ActiveKey = msg.SelectedKey;
|
ent.Comp.ActiveKey = msg.SelectedKey;
|
||||||
UpdateUserInterface(ent);
|
UpdateUserInterface(ent);
|
||||||
}
|
}
|
||||||
|
private void OnStatusFilterPressed(Entity<CriminalRecordsConsoleComponent> ent, ref CriminalRecordSetStatusFilter msg)
|
||||||
|
{
|
||||||
|
ent.Comp.FilterStatus = msg.FilterStatus;
|
||||||
|
UpdateUserInterface(ent);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnFiltersChanged(Entity<CriminalRecordsConsoleComponent> ent, ref SetStationRecordFilter msg)
|
private void OnFiltersChanged(Entity<CriminalRecordsConsoleComponent> ent, ref SetStationRecordFilter msg)
|
||||||
{
|
{
|
||||||
@@ -112,13 +120,26 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// will probably never fail given the checks above
|
// will probably never fail given the checks above
|
||||||
|
name = _records.RecordName(key.Value);
|
||||||
|
officer = Loc.GetString("criminal-records-console-unknown-officer");
|
||||||
|
var jobName = "Unknown";
|
||||||
|
|
||||||
|
_records.TryGetRecord<GeneralStationRecord>(key.Value, out var entry);
|
||||||
|
if (entry != null)
|
||||||
|
jobName = entry.JobTitle;
|
||||||
|
|
||||||
|
var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(null, mob.Value);
|
||||||
|
RaiseLocalEvent(tryGetIdentityShortInfoEvent);
|
||||||
|
if (tryGetIdentityShortInfoEvent.Title != null)
|
||||||
|
officer = tryGetIdentityShortInfoEvent.Title;
|
||||||
|
|
||||||
_criminalRecords.TryChangeStatus(key.Value, msg.Status, msg.Reason, officer);
|
_criminalRecords.TryChangeStatus(key.Value, msg.Status, msg.Reason, officer);
|
||||||
|
|
||||||
(string, object)[] args;
|
(string, object)[] args;
|
||||||
if (reason != null)
|
if (reason != null)
|
||||||
args = new (string, object)[] { ("name", name), ("officer", officer), ("reason", reason) };
|
args = new (string, object)[] { ("name", name), ("officer", officer), ("reason", reason), ("job", jobName) };
|
||||||
else
|
else
|
||||||
args = new (string, object)[] { ("name", name), ("officer", officer) };
|
args = new (string, object)[] { ("name", name), ("officer", officer), ("job", jobName) };
|
||||||
|
|
||||||
// figure out which radio message to send depending on transition
|
// figure out which radio message to send depending on transition
|
||||||
var statusString = (oldStatus, msg.Status) switch
|
var statusString = (oldStatus, msg.Status) switch
|
||||||
@@ -193,8 +214,18 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the listing of records to display
|
||||||
var listing = _records.BuildListing((owningStation.Value, stationRecords), console.Filter);
|
var listing = _records.BuildListing((owningStation.Value, stationRecords), console.Filter);
|
||||||
|
|
||||||
|
// filter the listing by the selected criminal record status
|
||||||
|
//if NONE, dont filter by status, just show all crew
|
||||||
|
if (console.FilterStatus != SecurityStatus.None)
|
||||||
|
{
|
||||||
|
listing = listing
|
||||||
|
.Where(x => _records.TryGetRecord<CriminalRecord>(new StationRecordKey(x.Key, owningStation.Value), out var record) && record.Status == console.FilterStatus)
|
||||||
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
|
}
|
||||||
|
|
||||||
var state = new CriminalRecordsConsoleState(listing, console.Filter);
|
var state = new CriminalRecordsConsoleState(listing, console.Filter);
|
||||||
if (console.ActiveKey is { } id)
|
if (console.ActiveKey is { } id)
|
||||||
{
|
{
|
||||||
@@ -205,6 +236,9 @@ public sealed class CriminalRecordsConsoleSystem : SharedCriminalRecordsConsoleS
|
|||||||
state.SelectedKey = id;
|
state.SelectedKey = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the Current Tab aka the filter status type for the records list
|
||||||
|
state.FilterStatus = console.FilterStatus;
|
||||||
|
|
||||||
_ui.SetUiState(uid, CriminalRecordsConsoleKey.Key, state);
|
_ui.SetUiState(uid, CriminalRecordsConsoleKey.Key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using Content.Shared.CriminalRecords.Systems;
|
using Content.Shared.CriminalRecords.Systems;
|
||||||
|
using Content.Shared.CriminalRecords.Components;
|
||||||
|
using Content.Shared.CriminalRecords;
|
||||||
using Content.Shared.Radio;
|
using Content.Shared.Radio;
|
||||||
using Content.Shared.StationRecords;
|
using Content.Shared.StationRecords;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Security;
|
||||||
|
|
||||||
namespace Content.Shared.CriminalRecords.Components;
|
namespace Content.Shared.CriminalRecords.Components;
|
||||||
|
|
||||||
@@ -31,6 +34,12 @@ public sealed partial class CriminalRecordsConsoleComponent : Component
|
|||||||
[DataField]
|
[DataField]
|
||||||
public StationRecordsFilter? Filter;
|
public StationRecordsFilter? Filter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current seleced security status for the filter by criminal status dropdown.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public SecurityStatus FilterStatus;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Channel to send messages to when someone's status gets changed.
|
/// Channel to send messages to when someone's status gets changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ public sealed class CriminalRecordsConsoleState : BoundUserInterfaceState
|
|||||||
/// Currently selected crewmember record key.
|
/// Currently selected crewmember record key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint? SelectedKey = null;
|
public uint? SelectedKey = null;
|
||||||
|
|
||||||
public CriminalRecord? CriminalRecord = null;
|
public CriminalRecord? CriminalRecord = null;
|
||||||
public GeneralStationRecord? StationRecord = null;
|
public GeneralStationRecord? StationRecord = null;
|
||||||
|
public SecurityStatus FilterStatus = SecurityStatus.None;
|
||||||
public readonly Dictionary<uint, string>? RecordListing;
|
public readonly Dictionary<uint, string>? RecordListing;
|
||||||
public readonly StationRecordsFilter? Filter;
|
public readonly StationRecordsFilter? Filter;
|
||||||
|
|
||||||
@@ -100,3 +100,20 @@ public sealed class CriminalRecordDeleteHistory : BoundUserInterfaceMessage
|
|||||||
Index = index;
|
Index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to set what status to filter by index.
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
|
||||||
|
public sealed class CriminalRecordSetStatusFilter : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public readonly SecurityStatus FilterStatus;
|
||||||
|
public CriminalRecordSetStatusFilter(SecurityStatus newFilterStatus)
|
||||||
|
{
|
||||||
|
FilterStatus = newFilterStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ criminal-records-console-records-list-title = Crewmembers
|
|||||||
criminal-records-console-select-record-info = Select a record.
|
criminal-records-console-select-record-info = Select a record.
|
||||||
criminal-records-console-no-records = No records found!
|
criminal-records-console-no-records = No records found!
|
||||||
criminal-records-console-no-record-found = No record was found for the selected person.
|
criminal-records-console-no-record-found = No record was found for the selected person.
|
||||||
|
criminal-records-console-flavor-left = Arrest first! Ask questions later.
|
||||||
|
criminal-records-console-flavor-right = v2.1
|
||||||
|
criminal-records-console-show-all = All
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
@@ -14,8 +17,8 @@ criminal-records-status-suspected = Suspect
|
|||||||
criminal-records-status-discharged = Discharged
|
criminal-records-status-discharged = Discharged
|
||||||
criminal-records-status-paroled = Paroled
|
criminal-records-status-paroled = Paroled
|
||||||
|
|
||||||
criminal-records-console-wanted-reason = [color=gray]Wanted Reason[/color]
|
criminal-records-console-wanted-reason = Wanted Reason
|
||||||
criminal-records-console-suspected-reason = [color=gray]Suspected Reason[/color]
|
criminal-records-console-suspected-reason = Suspected Reason
|
||||||
criminal-records-console-reason = Reason
|
criminal-records-console-reason = Reason
|
||||||
criminal-records-console-reason-placeholder = For example: {$placeholder}
|
criminal-records-console-reason-placeholder = For example: {$placeholder}
|
||||||
|
|
||||||
@@ -31,14 +34,14 @@ criminal-records-permission-denied = Permission denied
|
|||||||
|
|
||||||
## Security channel notifications
|
## Security channel notifications
|
||||||
|
|
||||||
criminal-records-console-wanted = {$name} was made wanted by {$officer} for: {$reason}.
|
criminal-records-console-wanted = {$name} ({$job}) was made wanted by {$officer} for: {$reason}.
|
||||||
criminal-records-console-suspected = {$officer} marked {$name} as suspicious because of: {$reason}
|
criminal-records-console-suspected = {$officer} marked {$name} ({$job}) as suspicious because of: {$reason}
|
||||||
criminal-records-console-not-suspected = {$name} has been cleared of suspicion by {$officer}.
|
criminal-records-console-not-suspected = {$name} ({$job}) has been cleared of suspicion by {$officer}.
|
||||||
criminal-records-console-detained = {$name} has been detained by {$officer}.
|
criminal-records-console-detained = {$name} ({$job}) has been detained by {$officer}.
|
||||||
criminal-records-console-released = {$name} has been released by {$officer}.
|
criminal-records-console-released = {$name} ({$job}) has been released by {$officer}.
|
||||||
criminal-records-console-not-wanted = {$officer} cleared the wanted status of {$name}.
|
criminal-records-console-not-wanted = {$officer} cleared the wanted status of {$name} ($job).
|
||||||
criminal-records-console-paroled = {$name} has been released on parole by {$officer}.
|
criminal-records-console-paroled = {$name} ({$job}) has been released on parole by {$officer}.
|
||||||
criminal-records-console-not-parole = {$officer} cleared the parole status of {$name}.
|
criminal-records-console-not-parole = {$officer} cleared the parole status of {$name} ({$job}).
|
||||||
criminal-records-console-unknown-officer = <unknown>
|
criminal-records-console-unknown-officer = <unknown>
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
- The criminal records themselves
|
- The criminal records themselves
|
||||||
|
|
||||||
|
- The filter button below the crew list can be used to show only wanted, detained, or paroled crew.
|
||||||
In the record section you can:
|
In the record section you can:
|
||||||
- See security-related information about a crewmember like their name, fingerprints and DNA.
|
- See security-related information about a crewmember like their name, fingerprints and DNA.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user