/*
* VideoKit
* Copyright © 2026 Yusuf Olokoba. All Rights Reserved.
*/
namespace VideoKit.UI {
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
///
/// Lightweight record button with press-and-hold gesture.
///
[RequireComponent(typeof(Image)), AddComponentMenu(@""), DisallowMultipleComponent]
public sealed class VideoKitRecordButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
#region --Inspector--
[Header(@"Settings")]
///
/// Maximum duration that button can be pressed.
///
[Range(5f, 60f), Tooltip(@"Maximum duration that button can be pressed.")]
public float maxDuration = 10f;
[Header(@"UI")]
///
/// Countdown image.
///
[Tooltip(@"Countdown image.")]
public Image countdown;
[Header(@"Events")]
///
/// Event invoked when the button is tapped.
///
[Tooltip(@"Event invoked when the button is tapped.")]
public UnityEvent OnTap;
///
/// Event invoked when the button starts being held.
///
[Tooltip(@"Event invoked when the button starts being held."), FormerlySerializedAs(@"OnStartRecording")]
public UnityEvent OnBeginHold;
///
/// Event invoked when the button stops being held.
///
[Tooltip(@"Event invoked when the button stops being held."), FormerlySerializedAs(@"OnStopRecording")]
public UnityEvent OnEndHold;
#endregion
#region --Operations--
private Image button;
private bool touch;
private const float TapDelay = 0.2f;
private void Awake() => button = GetComponent();
private void Start() => Zero();
private void Zero() {
button.fillAmount = 1.0f;
countdown.fillAmount = 0.0f;
}
private IEnumerator Countdown() {
touch = true;
// Wait for false touch
yield return new WaitForSeconds(TapDelay);
if (!touch) {
OnTap?.Invoke();
yield break;
}
// Start recording
OnBeginHold?.Invoke();
// Animate the countdown
var startTime = Time.time;
while (touch) {
var ratio = (Time.time - startTime) / maxDuration;
touch = ratio <= 1f;
countdown.fillAmount = ratio;
button.fillAmount = 1f - ratio;
yield return null;
}
// Reset
Zero();
OnEndHold?.Invoke();
}
void IPointerDownHandler.OnPointerDown(PointerEventData eventData) => StartCoroutine(Countdown());
void IPointerUpHandler.OnPointerUp(PointerEventData eventData) => touch = false;
#endregion
}
}