You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
6.6 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using WalletConnectUnity.Core.Utils;
using DeviceType = WalletConnectUnity.Core.Utils.DeviceType;
namespace WalletConnectUnity.UI
{
[AddComponentMenu("WalletConnect/UI/WC Modal")]
public class WCModal : MonoBehaviour
{
[Header("Scene References")]
[SerializeField] private Canvas _canvas;
[SerializeField] private RectTransform _rectTransform;
[SerializeField] private RectTransform _rootRectTransform;
[SerializeField] private CanvasScaler _rootCanvasScaler;
[SerializeField] private Canvas _globalBackgroundCanvas;
[SerializeField] private Image _modalMaskImage;
[SerializeField] private Image _modalBorderImage;
[field: SerializeField] public WCModalHeader Header { get; private set; }
[Header("Settings")]
[SerializeField, Range(0, 1)] private float _mobileMaxHeightPercent = 0.8f;
[SerializeField] private TransformConfig _mobileTransformConfig;
[SerializeField] private TransformConfig _desktopTransformConfig;
[Header("Asset References")]
[SerializeField] private Sprite _mobileModalMaskSprite;
[SerializeField] private Sprite _mobileModalBorderSprite;
public bool IsOpen => _canvas.enabled;
public Canvas Canvas => _canvas;
public RectTransform RootRectTransform => _rootRectTransform;
public float MobileMaxHeightPercent => _mobileMaxHeightPercent;
public event EventHandler Opened;
public event EventHandler Closed;
private readonly Stack<WCModalView> _viewsStack = new();
private bool _hasGlobalBackground;
private bool _resizingModal;
private Coroutine _backInputCoroutine;
private void Awake()
{
_hasGlobalBackground = _globalBackgroundCanvas != null;
HandleConstantPhysicalSize();
}
public void OpenView(WCModalView view, WCModal modal = null, object parameters = null)
{
if (_viewsStack.Count == 0)
EnableModal();
if (_viewsStack.Count > 0)
_viewsStack.Peek().Hide();
modal ??= this;
var resizeCoroutine = ResizeModalRoutine(view.GetViewHeight());
_viewsStack.Push(view);
view.Show(modal, resizeCoroutine, parameters);
Header.Title = view.GetTitle();
}
public void CloseView()
{
if (_viewsStack.Count <= 0) return;
var currentView = _viewsStack.Pop();
currentView.Hide();
if (_viewsStack.Count > 0)
{
var nextView = _viewsStack.Peek();
Header.Title = nextView.GetTitle();
var resizeCoroutine = ResizeModalRoutine(nextView.GetViewHeight());
nextView.Show(this, resizeCoroutine);
}
else
{
DisableModal();
}
}
public void CloseModal()
{
if (_viewsStack.Count > 0)
{
var lastView = _viewsStack.Pop();
lastView.Hide();
}
_viewsStack.Clear();
DisableModal();
if (_backInputCoroutine != null)
StopCoroutine(_backInputCoroutine);
Closed?.Invoke(this, EventArgs.Empty);
}
public IEnumerator ResizeModalRoutine(float targetHeight)
{
if (_resizingModal) yield break;
_resizingModal = true;
targetHeight = targetHeight + Header.Height + 12;
#if UNITY_ANDROID || UNITY_IOS
if (DeviceUtils.GetDeviceType() == DeviceType.Phone)
targetHeight += 8;
#endif
var rootTransformSizeDelta = _rectTransform.sizeDelta;
var originalHeight = rootTransformSizeDelta.y;
var elapsedTime = 0f;
var duration = .25f; // TODO: serialize this
targetHeight = Mathf.Min(targetHeight, _rootRectTransform.sizeDelta.y * _mobileMaxHeightPercent);
while (elapsedTime < duration)
{
var lerp = Mathf.Lerp(originalHeight, targetHeight, elapsedTime / duration);
_rectTransform.sizeDelta = new Vector2(rootTransformSizeDelta.x, lerp);
elapsedTime += Time.deltaTime;
yield return null;
}
_rectTransform.sizeDelta = new Vector2(rootTransformSizeDelta.x, targetHeight);
_resizingModal = false;
}
private void HandleConstantPhysicalSize()
{
const float targetDPI = 160;
// When using Game view instead of Device Simulator, you may want to change the target DPI for better scaling, e.g.:
// #if (UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS))
// targetDPI = 96;
// #endif
if (Screen.dpi != 0)
_rootCanvasScaler.scaleFactor = Screen.dpi / targetDPI;
else
_rootCanvasScaler.scaleFactor = 1f;
}
private void EnableModal()
{
var deviceType = DeviceUtils.GetDeviceType();
if (deviceType == DeviceType.Phone)
{
_mobileTransformConfig.Apply(_rectTransform);
_modalMaskImage.sprite = _mobileModalMaskSprite;
_modalBorderImage.sprite = _mobileModalBorderSprite;
OrientationTracker.Enable();
}
else
{
_desktopTransformConfig.Apply(_rectTransform);
}
_canvas.enabled = true;
if (_hasGlobalBackground)
_globalBackgroundCanvas.enabled = true;
_backInputCoroutine = StartCoroutine(BackInputRoutine());
Opened?.Invoke(this, EventArgs.Empty);
}
private void DisableModal()
{
_canvas.enabled = false;
if (_hasGlobalBackground)
_globalBackgroundCanvas.enabled = false;
#if UNITY_ANDROID || UNITY_IOS
OrientationTracker.Disable();
#endif
}
private IEnumerator BackInputRoutine()
{
while (_canvas.enabled)
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (_viewsStack.Count > 0)
{
CloseView();
}
else
{
CloseModal();
}
}
yield return null;
}
}
}
}