using System; using System.ComponentModel; using System.Linq; using System.Reflection; using UnityEngine; using UnityEngine.UI; using DDD.MVVM; namespace DDD { public abstract class BaseUi : MonoBehaviour { [SerializeField] protected bool _enableBlockImage; protected CanvasGroup _canvasGroup; protected GameObject _blockImage; protected GameObject _panel; protected BindingContext _bindingContext; public virtual bool IsBlockingTime => false; public virtual bool IsOpen => _panel != null && _panel.activeSelf; protected virtual void Awake() { _canvasGroup = GetComponent(); _panel = transform.Find(CommonConstants.Panel)?.gameObject; _blockImage = transform.Find(CommonConstants.BlockImage)?.gameObject; _bindingContext = new BindingContext(); SetupAutoBindings(); SetupBindings(); } protected virtual void OnEnable() { } protected virtual void Start() { TryRegister(); ClosePanel(); } protected virtual void Update() { } protected virtual void OnDisable() { } protected virtual void OnDestroy() { TryUnregister(); _bindingContext?.Dispose(); } protected virtual void TryRegister() { } protected virtual void TryUnregister() { } // BaseUi 메서드들을 직접 구현 public virtual void OpenPanel() { if (_enableBlockImage) { _blockImage.SetActive(true); } _panel.SetActive(true); } public virtual void ClosePanel() { if (_enableBlockImage) { _blockImage.SetActive(false); } _panel.SetActive(false); } public virtual void SetUiInteractable(bool active) { if (_canvasGroup != null) { _canvasGroup.interactable = active; _canvasGroup.blocksRaycasts = active; } } public bool IsOpenPanel() => _panel && _panel.activeInHierarchy; /// /// Attribute 기반 자동 바인딩 설정 /// private void SetupAutoBindings() { var fields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) .Where(f => f.GetCustomAttribute() != null); foreach (var field in fields) { var bindAttribute = field.GetCustomAttribute(); SetupBinding(field, bindAttribute); } // 컬렉션 바인딩 설정 var collectionFields = GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) .Where(f => f.GetCustomAttribute() != null); foreach (var field in collectionFields) { var bindAttribute = field.GetCustomAttribute(); SetupCollectionBinding(field, bindAttribute); } } /// /// 개별 필드의 바인딩 설정 /// private void SetupBinding(FieldInfo field, BindToAttribute bindAttribute) { var target = field.GetValue(this); IValueConverter converter = null; if (bindAttribute.ConverterType != null) { converter = Activator.CreateInstance(bindAttribute.ConverterType) as IValueConverter; } // UI 컴포넌트 타입별 바인딩 타겟 생성 IBindingTarget bindingTarget = target switch { Text text => new TextBindingTarget(text, bindAttribute.PropertyPath), Image image => new ImageBindingTarget(image, bindAttribute.PropertyPath), GameObject go => new ActiveBindingTarget(go, bindAttribute.PropertyPath), Slider slider => new SliderBindingTarget(slider, bindAttribute.PropertyPath), _ => null }; if (bindingTarget != null) { _bindingContext.Bind(bindAttribute.PropertyPath, bindingTarget, converter); } } /// /// 컬렉션 바인딩 설정 /// private void SetupCollectionBinding(FieldInfo field, BindCollectionAttribute bindAttribute) { var target = field.GetValue(this); if (target is Transform parent) { // 컬렉션 바인딩 로직 (필요시 확장) Debug.Log($"Collection binding for {bindAttribute.PropertyPath} is set up on {parent.name}"); } } /// /// 추가 바인딩 설정 - 하위 클래스에서 구현 /// protected virtual void SetupBindings() { } /// /// ViewModel 속성 변경 이벤트 핸들러 /// protected virtual void OnViewModelPropertyChanged(object sender, PropertyChangedEventArgs e) { HandleCustomPropertyChanged(e.PropertyName); } /// /// 커스텀 속성 변경 처리 (하위 클래스에서 오버라이드) /// protected virtual void HandleCustomPropertyChanged(string propertyName) { // 하위 클래스에서 구현 } // 수동 바인딩 헬퍼 메서드들 protected void BindText(Text text, string propertyPath, IValueConverter converter = null) { var target = new TextBindingTarget(text, propertyPath); _bindingContext?.Bind(propertyPath, target, converter); } protected void BindImage(Image image, string propertyPath, IValueConverter converter = null) { var target = new ImageBindingTarget(image, propertyPath); _bindingContext?.Bind(propertyPath, target, converter); } protected void BindActive(GameObject gameObject, string propertyPath, IValueConverter converter = null) { var target = new ActiveBindingTarget(gameObject, propertyPath); _bindingContext?.Bind(propertyPath, target, converter); } protected void BindSlider(Slider slider, string propertyPath, IValueConverter converter = null) { var target = new SliderBindingTarget(slider, propertyPath); _bindingContext?.Bind(propertyPath, target, converter); } } }