| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- using Content.Client.Popups;
- using Content.Client.UserInterface.Controls;
- using Content.Shared.Access.Systems;
- using Content.Shared.Holopad;
- using Content.Shared.Telephone;
- using Robust.Client.AutoGenerated;
- using Robust.Client.Graphics;
- using Robust.Client.Player;
- using Robust.Client.UserInterface.Controls;
- using Robust.Client.UserInterface.XAML;
- using Robust.Shared.Timing;
- using Robust.Shared.Utility;
- using System.Linq;
- namespace Content.Client.Holopad;
- [GenerateTypedNameReferences]
- public sealed partial class HolopadWindow : FancyWindow
- {
- [Dependency] private readonly IEntityManager _entManager = default!;
- [Dependency] private readonly IPlayerManager _playerManager = default!;
- [Dependency] private readonly IGameTiming _timing = default!;
- private readonly SharedHolopadSystem _holopadSystem = default!;
- private readonly SharedTelephoneSystem _telephoneSystem = default!;
- private readonly AccessReaderSystem _accessReaderSystem = default!;
- private readonly PopupSystem _popupSystem = default!;
- private EntityUid? _owner = null;
- private HolopadUiKey _currentUiKey;
- private TelephoneState _currentState;
- private TelephoneState _previousState;
- private TimeSpan _buttonUnlockTime;
- private float _updateTimer = 0.25f;
- private const float UpdateTime = 0.25f;
- private TimeSpan _buttonUnlockDelay = TimeSpan.FromSeconds(0.5f);
- public event Action<NetEntity>? SendHolopadStartNewCallMessageAction;
- public event Action? SendHolopadAnswerCallMessageAction;
- public event Action? SendHolopadEndCallMessageAction;
- public event Action? SendHolopadStartBroadcastMessageAction;
- public event Action? SendHolopadActivateProjectorMessageAction;
- public event Action? SendHolopadRequestStationAiMessageAction;
- public HolopadWindow()
- {
- RobustXamlLoader.Load(this);
- IoCManager.InjectDependencies(this);
- _holopadSystem = _entManager.System<SharedHolopadSystem>();
- _telephoneSystem = _entManager.System<SharedTelephoneSystem>();
- _accessReaderSystem = _entManager.System<AccessReaderSystem>();
- _popupSystem = _entManager.System<PopupSystem>();
- _buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
- // Assign button actions
- AnswerCallButton.OnPressed += args => { OnHolopadAnswerCallMessage(); };
- EndCallButton.OnPressed += args => { OnHolopadEndCallMessage(); };
- StartBroadcastButton.OnPressed += args => { OnHolopadStartBroadcastMessage(); };
- ActivateProjectorButton.OnPressed += args => { OnHolopadActivateProjectorMessage(); };
- RequestStationAiButton.OnPressed += args => { OnHolopadRequestStationAiMessage(); };
- // XML formatting
- AnswerCallButton.AddStyleClass("ButtonAccept");
- EndCallButton.AddStyleClass("Caution");
- StartBroadcastButton.AddStyleClass("Caution");
- HolopadContactListPanel.PanelOverride = new StyleBoxFlat
- {
- BackgroundColor = new Color(47, 47, 59) * Color.DarkGray,
- BorderColor = new Color(82, 82, 82), //new Color(70, 73, 102),
- BorderThickness = new Thickness(2),
- };
- HolopadContactListHeaderPanel.PanelOverride = new StyleBoxFlat
- {
- BackgroundColor = new Color(82, 82, 82),
- };
- EmergencyBroadcastText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-emergency-broadcast-in-progress")));
- SubtitleText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-subtitle")));
- OptionsText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-options")));
- }
- #region: Button actions
- private void OnSendHolopadStartNewCallMessage(NetEntity receiver)
- {
- SendHolopadStartNewCallMessageAction?.Invoke(receiver);
- }
- private void OnHolopadAnswerCallMessage()
- {
- SendHolopadAnswerCallMessageAction?.Invoke();
- }
- private void OnHolopadEndCallMessage()
- {
- SendHolopadEndCallMessageAction?.Invoke();
- if (_currentUiKey == HolopadUiKey.AiRequestWindow)
- Close();
- }
- private void OnHolopadStartBroadcastMessage()
- {
- if (_playerManager.LocalSession?.AttachedEntity == null || _owner == null)
- return;
- var player = _playerManager.LocalSession.AttachedEntity;
- if (!_accessReaderSystem.IsAllowed(player.Value, _owner.Value))
- {
- _popupSystem.PopupClient(Loc.GetString("holopad-window-access-denied"), _owner.Value, player.Value);
- return;
- }
- SendHolopadStartBroadcastMessageAction?.Invoke();
- }
- private void OnHolopadActivateProjectorMessage()
- {
- SendHolopadActivateProjectorMessageAction?.Invoke();
- }
- private void OnHolopadRequestStationAiMessage()
- {
- SendHolopadRequestStationAiMessageAction?.Invoke();
- }
- #endregion
- public void SetState(EntityUid owner, HolopadUiKey uiKey)
- {
- _owner = owner;
- _currentUiKey = uiKey;
- // Determines what UI containers are available to the user.
- // Components of these will be toggled on and off when
- // UpdateAppearance() is called
- switch (uiKey)
- {
- case HolopadUiKey.InteractionWindow:
- RequestStationAiContainer.Visible = true;
- HolopadContactListContainer.Visible = true;
- StartBroadcastContainer.Visible = true;
- break;
- case HolopadUiKey.InteractionWindowForAi:
- ActivateProjectorContainer.Visible = true;
- StartBroadcastContainer.Visible = true;
- break;
- case HolopadUiKey.AiActionWindow:
- HolopadContactListContainer.Visible = true;
- StartBroadcastContainer.Visible = true;
- break;
- case HolopadUiKey.AiRequestWindow:
- break;
- }
- }
- public void UpdateState(Dictionary<NetEntity, string> holopads)
- {
- if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
- return;
- // Caller ID text
- var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId.Item1, telephone.LastCallerId.Item2, Color.LightGray, "Default", 11);
- var holoapdId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId.Item3, Color.LightGray, "Default", 11);
- CallerIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
- HolopadIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(holoapdId));
- LockOutIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
- // Sort holopads alphabetically
- var holopadArray = holopads.ToArray();
- Array.Sort(holopadArray, AlphabeticalSort);
- // Clear excess children from the contact list
- while (ContactsList.ChildCount > holopadArray.Length)
- ContactsList.RemoveChild(ContactsList.GetChild(ContactsList.ChildCount - 1));
- // Make / update required children
- for (int i = 0; i < holopadArray.Length; i++)
- {
- var (netEntity, label) = holopadArray[i];
- if (i >= ContactsList.ChildCount)
- {
- var newContactButton = new HolopadContactButton();
- newContactButton.OnPressed += args => { OnSendHolopadStartNewCallMessage(newContactButton.NetEntity); };
- ContactsList.AddChild(newContactButton);
- }
- var child = ContactsList.GetChild(i);
- if (child is not HolopadContactButton)
- continue;
- var contactButton = (HolopadContactButton)child;
- contactButton.UpdateValues(netEntity, label);
- }
- // Update buttons
- UpdateAppearance();
- }
- private void UpdateAppearance()
- {
- if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
- return;
- if (_owner == null || !_entManager.TryGetComponent<HolopadComponent>(_owner.Value, out var holopad))
- return;
- var hasBroadcastAccess = !_holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad));
- var localPlayer = _playerManager.LocalSession?.AttachedEntity;
- ControlsLockOutContainer.Visible = _holopadSystem.IsHolopadControlLocked((_owner.Value, holopad), localPlayer);
- ControlsContainer.Visible = !ControlsLockOutContainer.Visible;
- // Temporarily disable the interface buttons when the call state changes to prevent any misclicks
- if (_currentState != telephone.CurrentState)
- {
- _previousState = _currentState;
- _currentState = telephone.CurrentState;
- _buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
- }
- var lockButtons = _timing.CurTime < _buttonUnlockTime;
- // Make / update required children
- foreach (var child in ContactsList.Children)
- {
- if (child is not HolopadContactButton contactButton)
- continue;
- var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) ||
- contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true;
- contactButton.Visible = passesFilter;
- contactButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
- }
- // Update control text
- var cooldown = _holopadSystem.GetHolopadBroadcastCoolDown((_owner.Value, holopad));
- var cooldownString = $"{cooldown.Minutes:00}:{cooldown.Seconds:00}";
- StartBroadcastButton.Text = _holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad)) ?
- Loc.GetString("holopad-window-emergency-broadcast-with-countdown", ("countdown", cooldownString)) :
- Loc.GetString("holopad-window-emergency-broadcast");
- var lockout = _holopadSystem.GetHolopadControlLockedPeriod((_owner.Value, holopad));
- var lockoutString = $"{lockout.Minutes:00}:{lockout.Seconds:00}";
- LockOutCountDownText.Text = Loc.GetString("holopad-window-controls-unlock-countdown", ("countdown", lockoutString));
- switch (_currentState)
- {
- case TelephoneState.Idle:
- CallStatusText.Text = Loc.GetString("holopad-window-no-calls-in-progress"); break;
- case TelephoneState.Calling:
- CallStatusText.Text = Loc.GetString("holopad-window-outgoing-call"); break;
- case TelephoneState.Ringing:
- CallStatusText.Text = (_currentUiKey == HolopadUiKey.AiRequestWindow) ?
- Loc.GetString("holopad-window-ai-request") : Loc.GetString("holopad-window-incoming-call"); break;
- case TelephoneState.InCall:
- CallStatusText.Text = Loc.GetString("holopad-window-call-in-progress"); break;
- case TelephoneState.EndingCall:
- if (_previousState == TelephoneState.Calling || _previousState == TelephoneState.Idle)
- CallStatusText.Text = Loc.GetString("holopad-window-call-rejected");
- else
- CallStatusText.Text = Loc.GetString("holopad-window-call-ending");
- break;
- }
- // Update control disability
- AnswerCallButton.Disabled = (_currentState != TelephoneState.Ringing || lockButtons);
- EndCallButton.Disabled = (_currentState == TelephoneState.Idle || _currentState == TelephoneState.EndingCall || lockButtons);
- StartBroadcastButton.Disabled = (_currentState != TelephoneState.Idle || !hasBroadcastAccess || lockButtons);
- RequestStationAiButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
- ActivateProjectorButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
- // Update control visibility
- FetchingAvailableHolopadsContainer.Visible = (ContactsList.ChildCount == 0);
- ActiveCallControlsContainer.Visible = (_currentState != TelephoneState.Idle || _currentUiKey == HolopadUiKey.AiRequestWindow);
- CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible;
- CallerIdContainer.Visible = (_currentState == TelephoneState.Ringing);
- AnswerCallButton.Visible = (_currentState == TelephoneState.Ringing);
- }
- protected override void FrameUpdate(FrameEventArgs args)
- {
- base.FrameUpdate(args);
- _updateTimer += args.DeltaSeconds;
- if (_updateTimer >= UpdateTime)
- {
- _updateTimer -= UpdateTime;
- UpdateAppearance();
- }
- }
- private sealed class HolopadContactButton : Button
- {
- public NetEntity NetEntity;
- public HolopadContactButton()
- {
- HorizontalExpand = true;
- SetHeight = 32;
- Margin = new Thickness(0f, 1f, 0f, 1f);
- ReservesSpace = false;
- }
- public void UpdateValues(NetEntity netEntity, string label)
- {
- NetEntity = netEntity;
- Text = Loc.GetString("holopad-window-contact-label", ("label", label));
- }
- }
- private int AlphabeticalSort(KeyValuePair<NetEntity, string> x, KeyValuePair<NetEntity, string> y)
- {
- if (string.IsNullOrEmpty(x.Value))
- return -1;
- if (string.IsNullOrEmpty(y.Value))
- return 1;
- return x.Value.CompareTo(y.Value);
- }
- }
|