using UnityEngine; using TMPro; using DG.Tweening; using System.Collections.Generic; using System.Collections; public enum NarrationID { Intro, NewEmail, ScanEmail, CorrectReportChoice, CorrectIgnoreChoice, WrongIgnoreChoice, Feedback, GameEnd } public class NarrationPlayer : MonoBehaviour { public static NarrationPlayer Instance { get; private set; } [Header("Narration Assets")] public List narrationDatabase; [Header("Subtitle Settings")] public TextMeshProUGUI subtitleText; public float charDelay = 0.03f; private AudioSource audioSource; private Tween typewriterTween; private Dictionary narrationMap; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); audioSource = gameObject.AddComponent(); audioSource.playOnAwake = false; narrationMap = new Dictionary(); foreach (var data in narrationDatabase) { if (data != null && !narrationMap.ContainsKey(data.narrationID)) narrationMap[data.narrationID] = data; } } public void PlayNarration(NarrationID id, System.Action onComplete = null) { if (!narrationMap.TryGetValue(id, out var narrationData)) { Debug.LogWarning($"Narration not found for: {id}"); return; } bool isArabic = LanguageManager.Instance.IsArabic; AudioClip clip = isArabic ? narrationData.arabicClip : narrationData.englishClip; if (clip == null) { Debug.LogWarning($"Missing audio clip for {id} in language: {(isArabic ? "Arabic" : "English")}"); return; } if (audioSource.isPlaying) audioSource.Stop(); audioSource.clip = clip; audioSource.Play(); if (!string.IsNullOrEmpty(narrationData.localizationKey)) { string rawSubtitle = LanguageManager.Instance.GetLocalizedText(narrationData.localizationKey); string subtitle = isArabic ? ArabicFixerHelper.FixPreservingTags(rawSubtitle) : rawSubtitle; // TMP settings per language subtitleText.font = LanguageManager.Instance.GetCurrentFont(); subtitleText.fontSize = isArabic ? 26 : 36; // subtitleText.alignment = isArabic ? TextAlignmentOptions.Right : TextAlignmentOptions.Left; subtitleText.overflowMode = TextOverflowModes.Page; subtitleText.isRightToLeftText = false; // MUST be false with ArabicFixer AppendSubtitle(subtitle, isArabic); } if (onComplete != null) StartCoroutine(InvokeAfterNarration(clip.length, onComplete)); } private void AppendSubtitle(string fullText, bool isArabic) { typewriterTween?.Kill(); subtitleText.text = ""; if (isArabic) { StartCoroutine(ShowArabicByPages(fullText)); return; } int totalLength = fullText.Length; int currentIndex = 0; typewriterTween = DOTween.To(() => currentIndex, x => { currentIndex = x; subtitleText.text = fullText.Substring(0, currentIndex); subtitleText.ForceMeshUpdate(); subtitleText.pageToDisplay = subtitleText.textInfo.pageCount; }, totalLength, totalLength * charDelay).SetEase(Ease.Linear); } private IEnumerator ShowArabicByPages(string fullText) { subtitleText.text = fullText; subtitleText.ForceMeshUpdate(); int totalPages = subtitleText.textInfo.pageCount; for (int i = 1; i <= totalPages; i++) { subtitleText.pageToDisplay = i; yield return new WaitForSeconds(5f); // Adjust delay per page } } private IEnumerator InvokeAfterNarration(float delay, System.Action callback) { yield return new WaitForSeconds(delay); callback?.Invoke(); } public void StopNarration() { if (audioSource.isPlaying) audioSource.Stop(); typewriterTween?.Kill(); } public void ClearSubtitles() { typewriterTween?.Kill(); subtitleText.text = ""; } public bool IsPlaying => audioSource.isPlaying; }