using System; using TMPro; using UnityEngine; using UVC.Extension; using UVC.UI; namespace UVC.Factory.Playback.UI { /// /// 재생 위치를 표시하고 조작할 수 있는 UI 프로그레스바 컴포넌트입니다. /// - 현재 재생 시간, 전체 시간, 슬라이더(Seek Bar)로 구성됩니다. /// - 슬라이더를 드래그하거나 클릭하여 재생 위치를 변경할 수 있습니다. /// /// 샘플 사용법: /// /// // UIPlaybackProgressBar를 가진 오브젝트를 찾고 초기화 /// var progressBar = FindObjectOfType<UIPlaybackProgressBar>(); /// progressBar.Init(1); // 1시간짜리 재생바로 초기화 /// /// // 값이 변경될 때마다 호출되는 콜백 등록 /// progressBar.OnChangeValue = (value) => { /// Debug.Log($"재생 위치가 {value}초로 변경됨"); /// }; /// /// // 재생 위치를 코드로 변경 /// progressBar.Value = 120; // 2분(120초) 위치로 이동 /// /// public class UIPlaybackProgressBar : MonoBehaviour { [Header("UI Playback Progress Bar")] [Tooltip("UI 활성/비활성 및 상호작용 제어용")] [SerializeField] private CanvasGroup canvasGroup;// UI 활성/비활성 및 상호작용 제어용 [Tooltip("현재 재생 시간 텍스트")] [SerializeField] private TextMeshProUGUI playTimeTxt;// 현재 재생 시간 텍스트 [Tooltip("전체 재생 시간 텍스트")] [SerializeField] private TextMeshProUGUI totalTimeTxt;// 전체 재생 시간 텍스트 [Tooltip("재생 위치를 조작하는 슬라이더")] [SerializeField] private SliderWithEvent progressBar;// 재생 위치를 조작하는 슬라이더 private float progressBarPrevValue = 0;// 이전 슬라이더 값(변경 감지용) // 전체 시간(시간 단위, 예: 1이면 1시간) private int time; /// /// 슬라이더 값이 변경될 때 호출되는 이벤트입니다. /// 예시: progressBar.OnChangeValue = (value) => { ... }; /// public Action OnChangeValue { get; set; } /// /// 현재 슬라이더(재생 위치) 값(초 단위)입니다. /// 값을 설정하면 UI와 내부 상태가 함께 갱신됩니다. /// public int Value { get { return (int)progressBar.value; } set { if (progressBar.value != value) { progressBar.value = value; UpdateTimeText(); progressBarPrevValue = value; } } } /// /// 슬라이더의 최대값(전체 재생 시간, 초 단위)입니다. /// public int MaxValue { get => (int)progressBar.maxValue; } /// /// 프로그레스바의 상호작용 가능 여부를 설정/조회합니다. /// public bool Interactable { get => canvasGroup.interactable; set => canvasGroup.interactable = value; } /// /// 오브젝트가 파괴될 때 이벤트 리스너를 해제합니다. /// private void OnDestroy() { progressBar.onValueChanged.RemoveListener(OnChangeSlider); progressBar.OnClickAction = null; progressBar.OnDragAction = null; progressBar.OnEndDragAction = null; } /// /// 프로그레스바를 초기화합니다. /// /// 전체 시간(시간 단위, 예: 1이면 1시간) /// /// progressBar.Init(1); // 1시간짜리 재생바로 초기화 /// public void Init(int time) { this.time = time; // 슬라이더 이벤트 등록 progressBar.onValueChanged.AddListener(OnChangeSlider); progressBar.OnClickAction += OnClickProgressBar; progressBar.OnDragAction += OnDragProgressBar; progressBar.OnEndDragAction += OnEndDragProgressBar; // 초기 텍스트 및 값 설정 playTimeTxt.text = $"{time.ToString("00")}:00:00"; totalTimeTxt.text = $"{(time + 1).ToString("00")}:00:00"; progressBar.value = 0; Interactable = true; } /// /// 슬라이더 값이 변경될 때 호출됩니다. /// 상호작용 불가 상태면 값을 되돌립니다. /// /// 변경된 값 private void OnChangeSlider(float newValue) { if (!Interactable) { progressBar.value = progressBarPrevValue; UpdateTimeText(); return; } } /// /// 슬라이더를 클릭했을 때 호출됩니다. /// 값이 변경되면 OnChangeValue 이벤트가 발생합니다. /// private void OnClickProgressBar() { float snapedValue = SnapProgressBarValue(); progressBar.value = snapedValue; UpdateTimeText(); if (progressBarPrevValue != snapedValue) { progressBarPrevValue = snapedValue; if (OnChangeValue != null) OnChangeValue.Invoke((int)snapedValue); } } /// /// 슬라이더를 드래그하는 동안 계속 호출됩니다. /// private void OnDragProgressBar() { float snapedValue = SnapProgressBarValue(); progressBar.value = snapedValue; UpdateTimeText(); } /// /// 슬라이더 드래그가 끝났을 때 호출됩니다. /// 값이 변경되면 OnChangeValue 이벤트가 발생합니다. /// private void OnEndDragProgressBar() { float snapedValue = SnapProgressBarValue(); progressBar.value = snapedValue; UpdateTimeText(); if (progressBarPrevValue != snapedValue) { progressBarPrevValue = snapedValue; if (OnChangeValue != null) OnChangeValue.Invoke((int)snapedValue); } } /// /// 슬라이더 값을 60초(1분) 단위로 스냅합니다. /// /// 스냅된 값 private float SnapProgressBarValue() { float value = progressBar.value; float interval = 60f; value = Mathf.Round(value / interval) * interval; return value; } /// /// 현재 재생 시간 텍스트를 갱신합니다. /// private void UpdateTimeText() { int minute = (int)progressBar.value / 60; int second = (int)progressBar.value % 60; string timeStr = time.ToString("00"); if (progressBar.value == 3600) { timeStr = (time + 1).ToString("00"); minute = 0; } playTimeTxt.text = $"{timeStr}:{minute.ToString("00")}:{second.ToString("00")}"; } } }