Files
EnglewoodLAB/Assets/Scripts/Factory/Playback/UI/UIPlayback.cs

279 lines
9.1 KiB
C#

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