284 lines
9.4 KiB
C#
284 lines
9.4 KiB
C#
using Cysharp.Threading.Tasks;
|
|
using System;
|
|
using UVC.UI.Loading;
|
|
|
|
namespace UVC.Factory.Playback.UI
|
|
{
|
|
/// <summary>
|
|
/// UIPlaybackController는 UIPlayback(View)에서 발생하는 이벤트를 받아
|
|
/// 실제 재생, 일시정지, 데이터 준비 등 비즈니스 로직을 처리하는 컨트롤러입니다.
|
|
///
|
|
/// <b>예시: UIPlayback과의 연결</b>
|
|
/// <code>
|
|
/// // UIPlayback에서 컨트롤러를 생성할 때 View를 넘겨줍니다.
|
|
/// var controller = new UIPlaybackController(this);
|
|
/// </code>
|
|
/// </summary>
|
|
public class UIPlaybackController : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// View 역할을 하는 UIPlayback 참조입니다.
|
|
/// </summary>
|
|
private readonly UIPlayback view;
|
|
|
|
// 재생 중 여부
|
|
private bool isPlaying = false;
|
|
// 데이터 준비 중 여부
|
|
private bool preparingData = false;
|
|
// 재생에 필요한 정보
|
|
private string date;
|
|
private string time;
|
|
private string fileName;
|
|
// 타이머 동작 여부
|
|
private bool isTick = false;
|
|
|
|
/// <summary>
|
|
/// 타이머 동작 여부를 외부에서 제어할 수 있습니다.
|
|
/// true로 설정하면 내부적으로 OnTimer()가 실행됩니다.
|
|
/// </summary>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 타이머를 시작하려면
|
|
/// controller.IsTick = true;
|
|
/// // 타이머를 멈추려면
|
|
/// controller.IsTick = false;
|
|
/// </code>
|
|
/// </example>
|
|
public bool IsTick
|
|
{
|
|
get => isTick;
|
|
set
|
|
{
|
|
if (isTick != value)
|
|
{
|
|
isTick = value;
|
|
if (isTick) OnTimer().Forget();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 생성자에서 View와 이벤트를 연결합니다.
|
|
/// </summary>
|
|
/// <param name="view">UIPlayback 인스턴스</param>
|
|
public UIPlaybackController(UIPlayback view)
|
|
{
|
|
this.view = view;
|
|
SubscribeToViewEvents();
|
|
}
|
|
|
|
/// <summary>
|
|
/// View에서 발생하는 이벤트를 컨트롤러의 메서드와 연결합니다.
|
|
/// </summary>
|
|
private void SubscribeToViewEvents()
|
|
{
|
|
view.OnClickExitButton += OnClickExit;
|
|
view.OnClickPlayButton += OnClickPlay;
|
|
view.OnChangeProgressValue += OnChangeProgress;
|
|
view.OnChangeSpeedValue += OnChangeSpeed;
|
|
view.OnChangeOpacityValue += OnValueChangedOpacity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 컨트롤러가 더 이상 필요 없을 때 이벤트 연결을 해제합니다.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
if (isPlaying) IsTick = false;
|
|
view.OnClickExitButton -= OnClickExit;
|
|
view.OnClickPlayButton -= OnClickPlay;
|
|
view.OnChangeProgressValue -= OnChangeProgress;
|
|
view.OnChangeSpeedValue -= OnChangeSpeed;
|
|
view.OnChangeOpacityValue -= OnValueChangedOpacity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생에 필요한 데이터를 설정하고 UI를 초기화합니다.
|
|
/// </summary>
|
|
/// <param name="date">날짜(예: "2024-07-29")</param>
|
|
/// <param name="time">시간(초 단위 문자열, 예: "3600")</param>
|
|
/// <param name="fileName">파일명</param>
|
|
/// <returns>비동기 작업(UniTask)</returns>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 재생 데이터를 설정하는 예시
|
|
/// await controller.SetData("2024-07-29", "3600", "sample.sqlite");
|
|
/// </code>
|
|
/// </example>
|
|
public async UniTask SetData(string date, string time, string fileName)
|
|
{
|
|
this.date = date;
|
|
this.time = time;
|
|
this.fileName = fileName;
|
|
|
|
int timeInt = int.Parse(time);
|
|
view.UpdateDateTime(date.Substring(2).Replace("-", "."));
|
|
view.InitProgressBar(timeInt);
|
|
view.InitSpeedSlider();
|
|
view.SetOpacity(1);
|
|
|
|
UpdateTimeScale(1);
|
|
preparingData = true;
|
|
view.SetUIInteractable(!preparingData);
|
|
isPlaying = false;
|
|
UpdatePlayState();
|
|
|
|
// 실제 데이터 로딩 (비동기)
|
|
await PlaybackService.Instance.DispatchBaseInfoData(date, time, fileName);
|
|
preparingData = false;
|
|
view.SetUIInteractable(!preparingData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 종료 버튼 클릭 시 호출됩니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// UI를 숨기고, 재생 상태를 초기화하며, PlaybackService에 종료를 알립니다.
|
|
/// </remarks>
|
|
private void OnClickExit()
|
|
{
|
|
UILoading.Show();
|
|
isPlaying = false;
|
|
UpdatePlayState();
|
|
view.Hide();
|
|
PlaybackService.Instance.Exit();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생/일시정지 버튼 클릭 시 호출됩니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 데이터 준비 중에는 동작하지 않습니다.
|
|
/// </remarks>
|
|
private void OnClickPlay()
|
|
{
|
|
if (preparingData) return;
|
|
isPlaying = !isPlaying;
|
|
UpdatePlayState();
|
|
}
|
|
|
|
// <summary>
|
|
/// 재생 위치(프로그레스바) 변경 시 호출됩니다.
|
|
/// </summary>
|
|
/// <param name="newValue">변경된 위치(초)</param>
|
|
private void OnChangeProgress(int newValue)
|
|
{
|
|
ChangePlayTime().Forget();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생 속도 변경 시 호출됩니다.
|
|
/// </summary>
|
|
/// <param name="newValue">변경된 속도 값</param>
|
|
private void OnChangeSpeed(int newValue)
|
|
{
|
|
UpdateTimeScale(isPlaying ? view.GetSpeedValue() : 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 투명도 슬라이더 변경 시 호출됩니다.
|
|
/// </summary>
|
|
/// <param name="newValue">0~1 사이의 투명도 값</param>
|
|
private void OnValueChangedOpacity(float newValue)
|
|
{
|
|
view.SetOpacity(newValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생/일시정지 상태에 따라 UI와 타이머를 갱신합니다.
|
|
/// </summary>
|
|
private void UpdatePlayState()
|
|
{
|
|
view.UpdatePlayButtonState(isPlaying);
|
|
IsTick = isPlaying;
|
|
OnChangeSpeed(view.GetSpeedValue());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생 위치를 변경할 때 호출됩니다.
|
|
/// 데이터 준비, UI 비활성화, 로딩 표시 등 처리 후 재생 위치를 이동합니다.
|
|
/// </summary>
|
|
private async UniTaskVoid ChangePlayTime()
|
|
{
|
|
bool tempIsPlaying = isPlaying;
|
|
isPlaying = false;
|
|
UpdatePlayState();
|
|
|
|
int newSecond = view.GetProgressValue();
|
|
if (newSecond == view.GetProgressMaxValue())
|
|
{
|
|
newSecond -= 60;
|
|
view.SetProgressValue(newSecond);
|
|
}
|
|
|
|
preparingData = true;
|
|
view.SetUIInteractable(!preparingData);
|
|
IsTick = false;
|
|
UILoading.Show();
|
|
|
|
|
|
int minute = newSecond / 60;
|
|
int seconds = newSecond % 60;
|
|
// 새로운 위치로 데이터 요청
|
|
await PlaybackService.Instance.DispatchBaseInfoData(date, time, fileName, minute.ToString("00"), seconds.ToString("00"));
|
|
|
|
preparingData = false;
|
|
view.SetUIInteractable(!preparingData);
|
|
|
|
if (tempIsPlaying)
|
|
{
|
|
isPlaying = true;
|
|
UpdatePlayState();
|
|
}
|
|
UILoading.Hide();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생 중일 때 일정 간격으로 호출되어 진행 바를 업데이트합니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// IsTick이 true일 때만 동작합니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 타이머를 시작하려면
|
|
/// controller.IsTick = true;
|
|
/// </code>
|
|
/// </example>
|
|
private async UniTaskVoid OnTimer()
|
|
{
|
|
if (view.GetProgressValue() >= view.GetProgressMaxValue())
|
|
{
|
|
if (isPlaying) OnClickPlay();
|
|
return;
|
|
}
|
|
|
|
view.SetProgressValue(view.GetProgressValue() + 1);
|
|
// 실시간 데이터 요청
|
|
PlaybackService.Instance.DispatchRealTimeData(view.GetProgressValue(), view.GetSpeedValue()).Forget();
|
|
|
|
if (IsTick)
|
|
{
|
|
// 재생 속도에 따라 대기 시간 조절
|
|
await UniTask.Delay(TimeSpan.FromMilliseconds(1000 / view.GetSpeedValue()));
|
|
if (IsTick) OnTimer().Forget();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재생 속도를 PlaybackService에 반영합니다.
|
|
/// </summary>
|
|
/// <param name="timeScale">적용할 재생 속도</param>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 재생 속도를 2배로 변경
|
|
/// controller.UpdateTimeScale(2f);
|
|
/// </code>
|
|
/// </example>
|
|
internal void UpdateTimeScale(float timeScale)
|
|
{
|
|
PlaybackService.Instance.TimeScale = timeScale;
|
|
}
|
|
}
|
|
}
|