using Cysharp.Threading.Tasks; using System; using TMPro; using UnityEngine; using UnityEngine.UI; using UVC.UI; namespace UVC.Factory.Playback.UI { /// /// 재생 UI를 관리하는 클래스입니다. /// - UI 요소의 표시/숨김, 버튼/슬라이더 등 UI 이벤트를 처리합니다. /// - 실제 재생 로직은 UIPlaybackController에서 처리합니다. /// public class UIPlayback : MonoBehaviour { // 싱글톤 패턴: 어디서든 UIPlayback.Instance로 접근할 수 있습니다. private static UIPlayback instance; public static UIPlayback Instance { get { if (instance == null) instance = CreateUIPlayBack(); return instance; } } /// /// UIPlayback 프리팹을 동적으로 생성합니다. /// /// 생성된 UIPlayback 인스턴스 private static UIPlayback CreateUIPlayBack() { // Resources 폴더에서 프리팹을 불러와 인스턴스화합니다. GameObject prefab = Resources.Load("Factory/Prefabs/Playback/UIPlayback"); GameObject go = GameObject.Instantiate(prefab); return go.GetComponent(); } // Inspector에서 연결할 UI 컴포넌트들입니다. [SerializeField] [Tooltip("종료 버튼")] private Button exitButton; [SerializeField] [Tooltip("종료 버튼")] private TextMeshProUGUI dateTimeTxt0; [SerializeField] [Tooltip("종료 버튼")] private TextMeshProUGUI dateTimeTxt1; [SerializeField] [Tooltip("play 버튼")] private Button playButton; [SerializeField] [Tooltip("play 버튼 이미지")] private Image playButtonImage; [SerializeField] [Tooltip("play 버튼 이미지 Sprite")] private Sprite playButtonImagePlay; [SerializeField] [Tooltip("play 버튼 Puase 이미지 Sprite")] private Sprite playButtonImagePause; [SerializeField] [Tooltip("Speed Slider")] private UISliderWithLabel sliderSpeed; [SerializeField] [Tooltip("투명 조절 Slider")] private SliderWithEvent opacitySlider; [SerializeField] [Tooltip("Progress Bar")] private UIPlaybackProgressBar progressBar; [SerializeField] private CanvasGroup canvasGroup; [SerializeField] private UIDragger uiDragger; // 컨트롤러: 실제 재생 로직을 담당합니다. private UIPlaybackController controller; // UI 이벤트를 외부(Controller)로 전달하기 위한 이벤트입니다. public event Action OnClickExitButton; public event Action OnClickPlayButton; public event Action OnChangeProgressValue; public event Action OnChangeSpeedValue; public event Action OnChangeOpacityValue; /// /// 오브젝트가 생성될 때 호출됩니다. /// private void Awake() { controller = new UIPlaybackController(this); Init(); } /// /// UI 이벤트 리스너를 등록합니다. /// private void Init() { // 버튼 클릭 시 이벤트 발생 exitButton.onClick.AddListener(() => OnClickExitButton?.Invoke()); playButton.onClick.AddListener(() => OnClickPlayButton?.Invoke()); // 슬라이더/프로그레스바 값 변경 시 이벤트 발생 progressBar.OnChangeValue += (value) => OnChangeProgressValue?.Invoke(value); sliderSpeed.OnChangeValue += (value) => OnChangeSpeedValue?.Invoke(value); opacitySlider.onValueChanged.AddListener((value) => OnChangeOpacityValue?.Invoke(value)); } /// /// 오브젝트가 파괴될 때 호출됩니다. /// private void OnDestroy() { // 모든 이벤트 리스너 해제 exitButton.onClick.RemoveAllListeners(); playButton.onClick.RemoveAllListeners(); progressBar.OnChangeValue = null; sliderSpeed.OnChangeValue = null; opacitySlider.onValueChanged.RemoveAllListeners(); controller.Dispose(); } /// /// UI를 화면에 표시합니다. /// /// /// /// // UIPlayback을 화면에 띄우는 예시 /// UIPlayback.Instance.Show(); /// /// public void Show() { if (playButton == null) Init(); gameObject.SetActive(true); if (transform.parent == null) { // ModalCanvas에 붙여서 항상 위에 보이도록 설정 var canvases = GameObject.FindObjectsByType(FindObjectsSortMode.None); foreach (var canvas in canvases) { if (canvas.name == "ModalCanvas") { transform.SetParent(canvas.transform, false); uiDragger.SetDragArea(canvas.transform as RectTransform); break; } } } } /// /// UI를 화면에서 숨깁니다. /// /// /// /// // UIPlayback을 숨기는 예시 /// UIPlayback.Instance.Hide(); /// /// public void Hide() { controller.UpdateTimeScale(1); controller.IsTick = false; gameObject.SetActive(false); } /// /// 재생에 필요한 데이터를 설정합니다. /// /// 날짜(예: "2024-07-29") /// 시간(초 단위 문자열, 예: "3600") /// 파일명 /// 비동기 작업(UniTask) /// /// /// await UIPlayback.Instance.SetData("2024-07-29", "3600", "sample.sqlite"); /// /// public UniTask SetData(string date, string time, string fileName) { return controller.SetData(date, time, fileName); } #region View Update Methods /// /// 날짜/시간 텍스트를 갱신합니다. /// /// 표시할 날짜 문자열 public void UpdateDateTime(string date) { dateTimeTxt0.text = dateTimeTxt1.text = date; } /// /// 재생 진행 바를 초기화합니다. /// /// 전체 재생 시간(초) public void InitProgressBar(int time) => progressBar.Init(time); /// /// 속도 슬라이더를 초기화합니다. /// public void InitSpeedSlider() => sliderSpeed.Init(); /// /// 재생/일시정지 버튼 이미지를 갱신합니다. /// /// 재생 중이면 true, 아니면 false public void UpdatePlayButtonState(bool isPlaying) { playButtonImage.sprite = isPlaying ? playButtonImagePause : playButtonImagePlay; } /// /// 재생 진행 바의 값을 설정합니다. /// /// 설정할 값(초) public void SetProgressValue(int value) { if (progressBar.Value != value) { progressBar.Value = value; } } /// /// 현재 재생 위치(초)를 반환합니다. /// public int GetProgressValue() => progressBar.Value; /// /// 전체 재생 시간(초)를 반환합니다. /// public int GetProgressMaxValue() => progressBar.MaxValue; /// /// 현재 선택된 재생 속도를 반환합니다. /// public int GetSpeedValue() => sliderSpeed.Value; /// /// UI의 투명도를 설정합니다. /// /// 0(완전 투명) ~ 1(완전 불투명) public void SetOpacity(float value) { canvasGroup.alpha = value; opacitySlider.value = value; } /// /// UI의 상호작용 가능 여부를 설정합니다. /// /// true면 버튼/슬라이더 사용 가능 public void SetUIInteractable(bool isInteractable) { playButton.enabled = isInteractable; progressBar.Interactable = isInteractable; } #endregion } }