using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; namespace Convai.Scripts.Utils { /// /// Base class for chat UI components, providing common functionality and abstract methods to be implemented by derived /// classes. /// public abstract class ChatUIBase : MonoBehaviour, IChatUI { [SerializeField] protected GameObject recordingMarker; private readonly List _characters = new(); [NonSerialized] protected GameObject UIInstance; private Image _recordingMarkerImage; private float _markerInitialAlpha; /// /// Initializes the recording marker and subscribes to the OnPlayerSpeakingChanged event. /// protected virtual void Start() { SetupMarkerImage(); SetRecordingMarkerActive(true); ConvaiGRPCAPI.Instance.OnPlayerSpeakingChanged += OnPlayerSpeakingChanged; } private void SetupMarkerImage() { if (recordingMarker == null) { throw new NullReferenceException("Recording Marker Image cannot be null, please assign an image for it"); } _recordingMarkerImage = recordingMarker.GetComponent(); if (_recordingMarkerImage == null) { throw new NullReferenceException("Recording Marker does not have an Image Component attached, system cannot work without it"); } _markerInitialAlpha = _recordingMarkerImage.color.a; } /// /// Initializes the UI with the provided prefab. /// /// The UI prefab to instantiate. public abstract void Initialize(GameObject uiPrefab); /// /// Activates the UI instance. /// public virtual void ActivateUI() { SetUIActive(true); } /// /// Deactivates the UI instance. /// public virtual void DeactivateUI() { SetUIActive(false); } /// /// Sends character text to the UI. /// /// The name of the character. /// The text to send. /// The color of the character's text. public abstract void SendCharacterText(string charName, string text, Color characterTextColor); /// /// Sends player text to the UI. /// /// The name of the player. /// The text to send. /// The color of the player's text. public abstract void SendPlayerText(string playerName, string text, Color playerTextColor); /// /// Retrieves the CanvasGroup component from the UI instance. /// /// The CanvasGroup component. public CanvasGroup GetCanvasGroup() { return UIInstance.GetComponent(); } /// /// Adds a character to the list of known characters if it does not already exist. /// /// The character to add. public void AddCharacter(Character character) { if (!HasCharacter(character.characterName)) _characters.Add(character); } /// /// Checks if a character with the given name exists in the list of known characters. /// /// The name of the character to check. /// True if the character exists, false otherwise. public bool HasCharacter(string characterName) { return _characters.Any(character => character.characterName == characterName); } /// /// Handles the player speaking state change by updating the recording marker's visibility. /// /// Whether the player is currently speaking. private void OnPlayerSpeakingChanged(bool isSpeaking) { if (_recordingMarkerImage != null) _recordingMarkerImage = _recordingMarkerImage.WithColorValue(a: isSpeaking ? 1.0f : _markerInitialAlpha); else Logger.Error("Image component not found on recording marker.", Logger.LogCategory.Character); } /// /// Sets the active state of the recording marker. /// /// The active state to set. private void SetRecordingMarkerActive(bool active) { if (recordingMarker != null) recordingMarker.SetActive(active); else Logger.Error("Recording marker GameObject is not assigned.", Logger.LogCategory.Character); } /// /// Sets the active state of the UI instance. /// /// The active state to set. private void SetUIActive(bool active) { if (UIInstance != null) UIInstance.SetActive(active); else Logger.Error("UI instance GameObject is not assigned.", Logger.LogCategory.Character); } } }