#nullable enable using Cysharp.Threading.Tasks; using System; using System.Collections.Generic; using UnityEngine; namespace UVC.UI.Tab { /// /// 탭 시스템을 제어하는 컨트롤러 클래스입니다. /// 설정 관리와 조정 역할만 담당하고, 실제 UI와 로딩은 TabView에서 처리합니다. /// /// /// 사용 예제: /// 1. TabContentConfig 설정 /// 2. 컨트롤러 초기화 /// /// public class TabSetup : MonoBehaviour /// { /// [SerializeField] /// protected TabController? tabController; /// /// protected virtual void Awake() /// { /// if (tabController == null) /// { /// Debug.LogError("TabController가 설정되지 않았습니다."); /// return; /// } /// /// // 코드로 탭 설정하기 /// SetupTabs(); /// } /// /// private void SetupTabs() /// { /// // 1. TabConfig 설정 /// tabController?.AddTabConfig("AGV", "AGV", "Prefabs/Factory/UI/Tab/DraggableListContent", null, CreateAGVData(), true); /// tabController?.AddTabConfig("ALARM", "ALARM", "Prefabs/Factory/UI/Tab/DraggableListContent", null, CreateAlarmData(), true); /// /// // 2. 컨트롤러 초기화 /// tabController?.Initialize(); /// } /// /// // 샘플 데이터 생성 메서드들 /// /// private object CreateAGVData() /// { /// Dictionary data = new Dictionary(); /// return data; /// } /// /// private object CreateAlarmData() /// { /// Dictionary data = new Dictionary(); /// return data; /// } /// } /// /// public class TabController : MonoBehaviour { [Header("탭 설정")] [Tooltip("탭 뷰 컴포넌트")] [SerializeField] private TabView? tabView; [Header("탭 컨텐츠")] [Tooltip("시작 시 자동 초기화 여부")] [SerializeField] private bool initializeOnStart = false; [Tooltip("탭 설정 목록")] [SerializeField] private TabContentConfig[] tabConfigs = new TabContentConfig[0]; // 탭 모델 private TabModel? _tabModel; // 초기화 여부 private bool _isInitialized = false; // 코드로 추가된 탭 설정 저장 private List _additionalTabConfigs = new List(); // 탭 변경 이벤트 public event Action? OnTabChanged; private void Awake() { _tabModel = new TabModel(); } private void Start() { if (initializeOnStart) { Initialize(); } } #region 코드 기반 탭 설정 관리 /// /// 코드에서 탭 설정을 추가합니다. /// public bool AddTabConfig(string id, string name, string path, string iconPath = "", object? data = null, bool useLazyLoading = false) { if (_isInitialized) { Debug.LogWarning("탭 시스템이 이미 초기화되었습니다."); return false; } var config = new TabContentConfig(id, name, path, iconPath, useLazyLoading, data); _additionalTabConfigs.Add(config); return true; } /// /// 모든 탭 설정을 가져옵니다. /// public List GetAllTabConfigs() { List allConfigs = new List(); // Inspector 설정 추가 foreach (var config in tabConfigs) { if (!string.IsNullOrEmpty(config.tabID) && !string.IsNullOrEmpty(config.contentPath)) { allConfigs.Add(config); } } // 코드로 추가된 설정 추가 allConfigs.AddRange(_additionalTabConfigs); return allConfigs; } #endregion #region 탭 시스템 초기화 및 관리 /// /// 탭 시스템을 초기화합니다. /// public void Initialize() { if (_isInitialized || _tabModel == null || tabView == null) return; // 탭 모델 초기화 InitializeModel(); // TabView에 설정 전달하여 초기화 List allConfigs = GetAllTabConfigs(); tabView.InitializeTabs(_tabModel.Tabs, allConfigs, OnTabButtonSelected); // 모델 이벤트 구독 _tabModel.OnTabChanged += HandleTabChanged; // 초기 탭 활성화 if (_tabModel.Tabs.Count > 0) { HandleTabChanged(_tabModel.ActiveTabIndex); } _isInitialized = true; } /// /// 탭 모델을 초기화합니다. /// private void InitializeModel() { if (_tabModel == null) return; List allConfigs = GetAllTabConfigs(); foreach (var config in allConfigs) { _tabModel.AddTab(new TabData( config.tabID, config.tabName, config.contentPath, config.tabIconPath, config.initialData )); } } /// /// 탭 버튼 선택 이벤트 처리 /// private void OnTabButtonSelected(int tabIndex) { _tabModel?.SwitchToTab(tabIndex); } /// /// 탭 변경 이벤트 처리 /// private void HandleTabChanged(int newTabIndex) { if (_tabModel == null || tabView == null) return; TabData? activeTabData = _tabModel.GetActiveTab(); if (activeTabData == null) return; // TabView에 탭 변경 전달 tabView.UpdateActiveTab(newTabIndex, _tabModel.PrevTabIndex, activeTabData).ContinueWith(() => { // 외부 이벤트 발생 OnTabChanged?.Invoke(newTabIndex); }); } #endregion #region 탭 활성화 및 데이터 관리 /// /// ID로 특정 탭을 활성화합니다. /// public void ActivateTab(string tabID) { _tabModel?.SwitchToTab(tabID); } /// /// 인덱스로 특정 탭을 활성화합니다. /// public void ActivateTab(int tabIndex) { _tabModel?.SwitchToTab(tabIndex); } /// /// 현재 활성화된 탭 인덱스를 반환합니다. /// public int GetActiveTabIndex() { return _tabModel?.ActiveTabIndex ?? -1; } /// /// 현재 활성화된 탭의 ID를 반환합니다. /// public string? GetActiveTabID() { TabData? activeTab = _tabModel?.GetActiveTab(); return activeTab?.tabID; } /// /// 특정 탭의 데이터를 설정하고 갱신합니다. /// public void SetTabContentData(string tabID, object? data) { if (_tabModel == null || tabView == null) return; // 모델 업데이트 _tabModel.UpdateTabContentData(tabID, data); // TabView에 업데이트 전달 int tabIndex = GetTabIndexByID(tabID); if (tabIndex >= 0) { tabView.UpdateTabContentData(tabIndex, data); } } /// /// 탭 ID로 인덱스를 찾습니다. /// private int GetTabIndexByID(string tabID) { if (_tabModel != null) { for (int i = 0; i < _tabModel.Tabs.Count; i++) { if (_tabModel.Tabs[i].tabID == tabID) { return i; } } } return -1; } #endregion #region TabView 위임 메서드 /// /// 특정 탭의 컨텐츠 인스턴스를 가져옵니다. /// public GameObject? GetTabInstance(string tabID, bool autoLoad = false) { return tabView?.GetTabInstance(tabID, autoLoad); } /// /// 특정 탭의 컴포넌트를 가져옵니다. /// public T? GetTabComponent(string tabID, bool autoLoad = false) where T : Component { return tabView?.GetTabComponent(tabID, autoLoad); } /// /// 특정 탭이 로드되었는지 확인합니다. /// public bool IsTabLoaded(string tabID) { return tabView?.IsTabLoaded(tabID) ?? false; } /// /// 현재 활성화된 탭을 제외한 모든 지연 로드 탭을 언로드합니다. /// public void UnloadAllExceptCurrent() { int currentIndex = GetActiveTabIndex(); tabView?.UnloadAllExceptCurrent(currentIndex); } /// /// 특정 탭의 컨텐츠를 언로드합니다. /// public bool UnloadTabContent(string tabID) { return tabView?.UnloadTabContent(tabID) ?? false; } /// /// 모든 탭 컨텐츠를 미리 로드합니다. /// public void PreloadAllTabs() { tabView?.PreloadAllTabs(); } #endregion private void OnDestroy() { if (_tabModel != null) { _tabModel.OnTabChanged -= HandleTabChanged; } } } }