275 lines
9.8 KiB
C#
275 lines
9.8 KiB
C#
using Cysharp.Threading.Tasks;
|
|
using DG.Tweening;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEditor.Search;
|
|
using UnityEngine;
|
|
using UVC.Log;
|
|
using UVC.Util;
|
|
|
|
namespace UVC.UI.Modal.DatePicker
|
|
{
|
|
public class DatePicker : MonoBehaviour
|
|
{
|
|
private static string PrefabPath = "Prefabs/UI/Modal/DatePicker/DatePicker";
|
|
private const string blockerPrefabPath = "Prefabs/UI/Modal/ModalBlocker"; //menu blocker prefab path
|
|
private static DatePicker instance;
|
|
private static Action<DateTime> _onDateSelectedCallback;
|
|
|
|
private Canvas parentCanvas;
|
|
|
|
private static GameObject? blockerPrefabObj;
|
|
private static GameObject currentBlockerInstance;
|
|
|
|
[Header("Calendar")]
|
|
[SerializeField]
|
|
public GameObject _calendarPanel;
|
|
[SerializeField]
|
|
public TextMeshProUGUI _yearNumText;
|
|
[SerializeField]
|
|
public TextMeshProUGUI _monthNumText;
|
|
[SerializeField]
|
|
public GameObject _item;
|
|
|
|
|
|
[Header("Colors")]
|
|
[SerializeField]
|
|
public Color textColor = ColorUtil.FromHex("808080");
|
|
[SerializeField]
|
|
public Color selectColor = ColorUtil.FromHex("F5A623");
|
|
[SerializeField]
|
|
public Color todayColor = Color.white;
|
|
[SerializeField]
|
|
public Color saturdayColor = ColorUtil.FromHex("4A90E2");
|
|
[SerializeField]
|
|
public Color sundayColor = ColorUtil.FromHex("FF5E5E");
|
|
|
|
private List<GameObject> _dateItems = new List<GameObject>();
|
|
private const int _totalDateNum = 42;
|
|
|
|
private DateTime _initTime;
|
|
private DateTime _dateTime;
|
|
|
|
|
|
public static async UniTask Show(DateTime initialDate, Action<DateTime> onDateSelected)
|
|
{
|
|
bool hasInstance = true;
|
|
if (instance == null)
|
|
{
|
|
hasInstance = false;
|
|
var prefab = await Resources.LoadAsync<DatePicker>(PrefabPath) as DatePicker;
|
|
instance = Instantiate(prefab);
|
|
if (instance == null)
|
|
{
|
|
Debug.LogError("No DatePicker prefab active on 'Start' in scene");
|
|
return;
|
|
}
|
|
Canvas[] canvases = FindObjectsByType<Canvas>(FindObjectsSortMode.None);
|
|
//sortingOrder로 정렬 내림차순 - sortingOrder가 높은 캔버스가 먼저 오도록
|
|
Array.Sort(canvases, (x, y) => y.sortingOrder.CompareTo(x.sortingOrder));
|
|
foreach (Canvas c in canvases)
|
|
{
|
|
if (c.renderMode != RenderMode.WorldSpace)
|
|
{
|
|
instance.transform.SetParent(c.transform, false);
|
|
instance.parentCanvas = c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
instance.gameObject.SetActive(true);
|
|
instance._initTime = initialDate;
|
|
instance._dateTime = initialDate;
|
|
|
|
//화면 센터에 위치 시키기
|
|
RectTransform rectTransform = instance.GetComponent<RectTransform>();
|
|
rectTransform.anchoredPosition = new Vector2((Screen.width - rectTransform.sizeDelta.x) / 2, -(Screen.height - rectTransform.sizeDelta.y) / 2);
|
|
_onDateSelectedCallback = onDateSelected;
|
|
|
|
if (hasInstance) instance.CreateCalendar();
|
|
|
|
ShowBlock();
|
|
}
|
|
|
|
public static void Hide()
|
|
{
|
|
if (instance != null) instance.gameObject.SetActive(false);
|
|
_onDateSelectedCallback = null; // 콜백 참조 정리
|
|
HideBlock();
|
|
}
|
|
|
|
private static async void ShowBlock()
|
|
{
|
|
if (blockerPrefabObj == null)
|
|
{
|
|
blockerPrefabObj = await Resources.LoadAsync<GameObject>(blockerPrefabPath) as GameObject;
|
|
}
|
|
if (blockerPrefabObj != null)
|
|
{
|
|
// 화면에서 가장 큰 그림판(Canvas)을 찾아서 그 위에 방패를 놓을 거예요.
|
|
Canvas mainCanvasForBlocker = instance.parentCanvas;
|
|
if (mainCanvasForBlocker != null)
|
|
{
|
|
// 방패를 복제해서(Instantiate) 그림판 위에 놓고, 가장 위로 오도록 순서를 조정해요.
|
|
currentBlockerInstance = UnityEngine.Object.Instantiate(blockerPrefabObj, mainCanvasForBlocker.transform);
|
|
int siblingIndex = instance.transform.GetSiblingIndex();
|
|
currentBlockerInstance.transform.SetSiblingIndex(Math.Max(0, siblingIndex - 1));
|
|
|
|
// 방패가 부드럽게 나타나도록 CanvasGroup 컴포넌트를 사용해요. 없으면 새로 추가!
|
|
CanvasGroup blockerCanvasGroup = currentBlockerInstance.GetComponent<CanvasGroup>();
|
|
if (blockerCanvasGroup == null) blockerCanvasGroup = currentBlockerInstance.AddComponent<CanvasGroup>();
|
|
blockerCanvasGroup.alpha = 0f;// 처음엔 완전히 투명하게
|
|
blockerCanvasGroup.DOFade(0.7f, 0.3f);// 0.3초 동안 서서히 나타나게 (투명도 70%)
|
|
}
|
|
else ULog.Error("[Modal] UIBlocker를 표시할 Canvas를 찾을 수 없습니다."); // 그림판을 못 찾으면 에러!
|
|
}
|
|
else ULog.Warning($"[Modal] UIBlocker 프리팹을 다음 경로에서 찾을 수 없습니다: {blockerPrefabPath}");
|
|
}
|
|
|
|
private static void HideBlock()
|
|
{
|
|
if (currentBlockerInstance != null)
|
|
{
|
|
var blockerCG = currentBlockerInstance.GetComponent<CanvasGroup>();
|
|
if (blockerCG != null)
|
|
{
|
|
blockerCG.DOFade(0f, 0.3f).OnComplete(() => {
|
|
UnityEngine.Object.Destroy(currentBlockerInstance); // 완전히 제거
|
|
}); // 부드럽게 사라지게
|
|
}
|
|
}
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
|
|
Vector3 startPos = _item.transform.localPosition;
|
|
_dateItems.Clear();
|
|
_dateItems.Add(_item);
|
|
|
|
for (int i = 1; i < _totalDateNum; i++)
|
|
{
|
|
GameObject item = GameObject.Instantiate(_item) as GameObject;
|
|
item.name = "Item" + (i + 1).ToString();
|
|
item.transform.SetParent(_item.transform.parent);
|
|
item.transform.localScale = Vector3.one;
|
|
item.transform.localRotation = Quaternion.identity;
|
|
item.transform.localPosition = new Vector3((i % 7) * 36 + startPos.x, startPos.y - (i / 7) * 30, startPos.z);
|
|
|
|
_dateItems.Add(item);
|
|
}
|
|
|
|
//_dateTime = DateTime.Now;
|
|
|
|
CreateCalendar();
|
|
}
|
|
|
|
void CreateCalendar()
|
|
{
|
|
|
|
DateTime firstDay = _dateTime.AddDays(-(_dateTime.Day - 1));
|
|
int index = GetDays(firstDay.DayOfWeek);
|
|
|
|
int date = 0;
|
|
for (int i = 0; i < _totalDateNum; i++)
|
|
{
|
|
TextMeshProUGUI label = _dateItems[i].GetComponentInChildren<TextMeshProUGUI>();
|
|
_dateItems[i].SetActive(false);
|
|
|
|
DateTime day = firstDay.AddDays(date);
|
|
|
|
Color txtColor = textColor;
|
|
//토요일 색 변경
|
|
if (day.DayOfWeek == DayOfWeek.Saturday) //토요일
|
|
{
|
|
txtColor = saturdayColor;
|
|
}
|
|
else if (day.DayOfWeek == DayOfWeek.Sunday) //일요일
|
|
{
|
|
txtColor = sundayColor;
|
|
}
|
|
|
|
//오늘 날짜인지 확인해서 text 색 변경
|
|
if (day.Date == DateTime.Now.Date)
|
|
{
|
|
txtColor = todayColor;
|
|
}
|
|
|
|
|
|
if (day.Date == _initTime.Date)
|
|
{
|
|
//_initTime날짜와 같은 날짜면 색 변경
|
|
txtColor = selectColor;
|
|
}
|
|
|
|
label.color = txtColor;
|
|
|
|
if (i >= index)
|
|
{
|
|
DateTime thatDay = firstDay.AddDays(date);
|
|
if (thatDay.Month == firstDay.Month)
|
|
{
|
|
_dateItems[i].SetActive(true);
|
|
|
|
label.text = (date + 1).ToString();
|
|
date++;
|
|
}
|
|
}
|
|
}
|
|
_yearNumText.text = _dateTime.Year.ToString();
|
|
_monthNumText.text = _dateTime.Month.ToString("D2");
|
|
}
|
|
|
|
int GetDays(DayOfWeek day)
|
|
{
|
|
switch (day)
|
|
{
|
|
case DayOfWeek.Monday: return 1;
|
|
case DayOfWeek.Tuesday: return 2;
|
|
case DayOfWeek.Wednesday: return 3;
|
|
case DayOfWeek.Thursday: return 4;
|
|
case DayOfWeek.Friday: return 5;
|
|
case DayOfWeek.Saturday: return 6;
|
|
case DayOfWeek.Sunday: return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
public void YearPrev()
|
|
{
|
|
_dateTime = _dateTime.AddYears(-1);
|
|
CreateCalendar();
|
|
}
|
|
|
|
public void YearNext()
|
|
{
|
|
_dateTime = _dateTime.AddYears(1);
|
|
CreateCalendar();
|
|
}
|
|
|
|
public void MonthPrev()
|
|
{
|
|
_dateTime = _dateTime.AddMonths(-1);
|
|
CreateCalendar();
|
|
}
|
|
|
|
public void MonthNext()
|
|
{
|
|
_dateTime = _dateTime.AddMonths(1);
|
|
CreateCalendar();
|
|
}
|
|
|
|
//Item 클릭했을 경우 Text에 표시.
|
|
public void OnDateItemClick(string day)
|
|
{
|
|
string date = _yearNumText.text + "-" + _monthNumText.text + "-" + int.Parse(day).ToString("D2");
|
|
_onDateSelectedCallback?.Invoke(DateTime.Parse(date));
|
|
Hide();
|
|
}
|
|
|
|
}
|
|
|
|
} |