219 lines
7.5 KiB
C#
219 lines
7.5 KiB
C#
using System;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UVC.Extension;
|
|
using UVC.UI;
|
|
|
|
namespace UVC.Factory.Playback.UI
|
|
{
|
|
/// <summary>
|
|
/// 재생 위치를 표시하고 조작할 수 있는 UI 프로그레스바 컴포넌트입니다.
|
|
/// - 현재 재생 시간, 전체 시간, 슬라이더(Seek Bar)로 구성됩니다.
|
|
/// - 슬라이더를 드래그하거나 클릭하여 재생 위치를 변경할 수 있습니다.
|
|
///
|
|
/// <para>샘플 사용법:</para>
|
|
/// <code>
|
|
/// // UIPlaybackProgressBar를 가진 오브젝트를 찾고 초기화
|
|
/// var progressBar = FindObjectOfType<UIPlaybackProgressBar>();
|
|
/// progressBar.Init(1); // 1시간짜리 재생바로 초기화
|
|
///
|
|
/// // 값이 변경될 때마다 호출되는 콜백 등록
|
|
/// progressBar.OnChangeValue = (value) => {
|
|
/// Debug.Log($"재생 위치가 {value}초로 변경됨");
|
|
/// };
|
|
///
|
|
/// // 재생 위치를 코드로 변경
|
|
/// progressBar.Value = 120; // 2분(120초) 위치로 이동
|
|
/// </code>
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// 슬라이더 값이 변경될 때 호출되는 이벤트입니다.
|
|
/// <para>예시: progressBar.OnChangeValue = (value) => { ... };</para>
|
|
/// </summary>
|
|
public Action<int> OnChangeValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// 현재 슬라이더(재생 위치) 값(초 단위)입니다.
|
|
/// 값을 설정하면 UI와 내부 상태가 함께 갱신됩니다.
|
|
/// </summary>
|
|
public int Value
|
|
{
|
|
get
|
|
{
|
|
return (int)progressBar.value;
|
|
}
|
|
|
|
set
|
|
{
|
|
if (progressBar.value != value)
|
|
{
|
|
progressBar.value = value;
|
|
UpdateTimeText();
|
|
progressBarPrevValue = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더의 최대값(전체 재생 시간, 초 단위)입니다.
|
|
/// </summary>
|
|
public int MaxValue
|
|
{
|
|
get => (int)progressBar.maxValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 프로그레스바의 상호작용 가능 여부를 설정/조회합니다.
|
|
/// </summary>
|
|
public bool Interactable
|
|
{
|
|
get => canvasGroup.interactable;
|
|
set => canvasGroup.interactable = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 오브젝트가 파괴될 때 이벤트 리스너를 해제합니다.
|
|
/// </summary>
|
|
private void OnDestroy()
|
|
{
|
|
progressBar.onValueChanged.RemoveListener(OnChangeSlider);
|
|
progressBar.OnClickAction = null;
|
|
progressBar.OnDragAction = null;
|
|
progressBar.OnEndDragAction = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 프로그레스바를 초기화합니다.
|
|
/// </summary>
|
|
/// <param name="time">전체 시간(시간 단위, 예: 1이면 1시간)</param>
|
|
/// <example>
|
|
/// progressBar.Init(1); // 1시간짜리 재생바로 초기화
|
|
/// </example>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더 값이 변경될 때 호출됩니다.
|
|
/// 상호작용 불가 상태면 값을 되돌립니다.
|
|
/// </summary>
|
|
/// <param name="newValue">변경된 값</param>
|
|
private void OnChangeSlider(float newValue)
|
|
{
|
|
if (!Interactable)
|
|
{
|
|
progressBar.value = progressBarPrevValue;
|
|
UpdateTimeText();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더를 클릭했을 때 호출됩니다.
|
|
/// 값이 변경되면 OnChangeValue 이벤트가 발생합니다.
|
|
/// </summary>
|
|
private void OnClickProgressBar()
|
|
{
|
|
float snapedValue = SnapProgressBarValue();
|
|
progressBar.value = snapedValue;
|
|
UpdateTimeText();
|
|
if (progressBarPrevValue != snapedValue)
|
|
{
|
|
progressBarPrevValue = snapedValue;
|
|
if (OnChangeValue != null) OnChangeValue.Invoke((int)snapedValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더를 드래그하는 동안 계속 호출됩니다.
|
|
/// </summary>
|
|
private void OnDragProgressBar()
|
|
{
|
|
float snapedValue = SnapProgressBarValue();
|
|
progressBar.value = snapedValue;
|
|
UpdateTimeText();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더 드래그가 끝났을 때 호출됩니다.
|
|
/// 값이 변경되면 OnChangeValue 이벤트가 발생합니다.
|
|
/// </summary>
|
|
private void OnEndDragProgressBar()
|
|
{
|
|
float snapedValue = SnapProgressBarValue();
|
|
progressBar.value = snapedValue;
|
|
UpdateTimeText();
|
|
if (progressBarPrevValue != snapedValue)
|
|
{
|
|
progressBarPrevValue = snapedValue;
|
|
if (OnChangeValue != null) OnChangeValue.Invoke((int)snapedValue);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 슬라이더 값을 60초(1분) 단위로 스냅합니다.
|
|
/// </summary>
|
|
/// <returns>스냅된 값</returns>
|
|
private float SnapProgressBarValue()
|
|
{
|
|
float value = progressBar.value;
|
|
float interval = 60f;
|
|
value = Mathf.Round(value / interval) * interval;
|
|
return value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 재생 시간 텍스트를 갱신합니다.
|
|
/// </summary>
|
|
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")}";
|
|
}
|
|
|
|
}
|
|
}
|