using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace InteractiveVideo.Examples
{
///
/// Minimal transport for testing: play/pause button, scrub slider, frame label, highlight-mode cycling and a
/// debug toggle. Not part of the core system.
///
[AddComponentMenu("Interactive Video/Examples/Demo Controls")]
public sealed class InteractiveVideoDemoControls : MonoBehaviour
{
[SerializeField] private InteractiveVideoPlayer player;
[SerializeField] private VideoTrackingManager trackingManager;
[SerializeField] private VideoHighlightController highlightController;
[Header("UI")]
[SerializeField] private Button playPauseButton;
[SerializeField] private TMP_Text playPauseLabel;
[SerializeField] private Slider scrubber;
[SerializeField] private TMP_Text frameLabel;
[SerializeField] private Button modeButton;
[SerializeField] private TMP_Text modeLabel;
[SerializeField] private Toggle debugToggle;
private float _scrubHoldUntil = -1f;
private long _lastFrame = long.MinValue;
private void Awake()
{
if (player == null) player = FindAnyObjectByType();
if (player != null)
{
if (trackingManager == null) trackingManager = player.TrackingManager;
if (highlightController == null) highlightController = player.HighlightController;
}
}
private void OnEnable()
{
if (playPauseButton != null) playPauseButton.onClick.AddListener(OnPlayPause);
if (modeButton != null) modeButton.onClick.AddListener(OnCycleMode);
if (scrubber != null) scrubber.onValueChanged.AddListener(OnScrub);
if (debugToggle != null)
{
debugToggle.SetIsOnWithoutNotify(trackingManager != null && trackingManager.ShowTrackingDebug);
debugToggle.onValueChanged.AddListener(OnDebugToggled);
}
UpdateModeLabel();
}
private void OnDisable()
{
if (playPauseButton != null) playPauseButton.onClick.RemoveListener(OnPlayPause);
if (modeButton != null) modeButton.onClick.RemoveListener(OnCycleMode);
if (scrubber != null) scrubber.onValueChanged.RemoveListener(OnScrub);
if (debugToggle != null) debugToggle.onValueChanged.RemoveListener(OnDebugToggled);
}
private void Update()
{
if (player == null) return;
if (playPauseLabel != null)
{
string want = player.IsPlaying ? "Pause" : "Play";
if (playPauseLabel.text != want) playPauseLabel.text = want;
}
long frame = player.CurrentFrame;
if (frame == _lastFrame) return;
_lastFrame = frame;
if (frameLabel != null)
frameLabel.text = player.IsPrepared ? $"{frame} / {player.FrameCount}" : "-";
// Seeks are asynchronous: keep the slider under the user's control for a moment so the old frame
// does not yank it back before seekCompleted arrives.
if (scrubber != null && Time.unscaledTime > _scrubHoldUntil && player.IsPrepared && player.FrameCount > 1)
scrubber.SetValueWithoutNotify((float)frame / (player.FrameCount - 1));
}
private void OnPlayPause() => player?.TogglePlayPause();
private void OnScrub(float value)
{
if (player == null || !player.IsPrepared) return;
_scrubHoldUntil = Time.unscaledTime + 0.3f;
player.SeekNormalized(value);
}
private void OnCycleMode()
{
if (highlightController == null) return;
int next = ((int)highlightController.Mode + 1) % 5;
highlightController.SetHighlightMode(next);
UpdateModeLabel();
}
private void UpdateModeLabel()
{
if (modeLabel != null && highlightController != null) modeLabel.text = highlightController.Mode.ToString();
}
private void OnDebugToggled(bool on)
{
if (trackingManager != null) trackingManager.ShowTrackingDebug = on;
}
}
}