Files
EnglewoodLAB/Assets/Scripts/UVC/UI/Tab/TabController.cs

376 lines
12 KiB
C#

#nullable enable
using Cysharp.Threading.Tasks;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UVC.UI.Tab
{
/// <summary>
/// 탭 시스템을 제어하는 컨트롤러 클래스입니다.
/// 설정 관리와 조정 역할만 담당하고, 실제 UI와 로딩은 TabView에서 처리합니다.
/// </summary>
/// <example>
/// <b>사용 예제:</b>
/// 1. TabContentConfig 설정
/// 2. 컨트롤러 초기화
/// <code>
/// 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", "Factory/Prefabs/UI/Tab/DraggableListContent", null, CreateAGVData(), true);
/// tabController?.AddTabConfig("ALARM", "ALARM", "Factory/Prefabs/UI/Tab/DraggableListContent", null, CreateAlarmData(), true);
///
/// // 2. 컨트롤러 초기화
/// tabController?.Initialize();
/// }
///
/// // 샘플 데이터 생성 메서드들
///
/// private object CreateAGVData()
/// {
/// Dictionary<string, string> updateData = new Dictionary<string, string>();
/// return updateData;
/// }
///
/// private object CreateAlarmData()
/// {
/// Dictionary<string, string> updateData = new Dictionary<string, string>();
/// return updateData;
/// }
/// }
/// </code>
/// </example>
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];
[Tooltip("활성화 탭 버튼을 클릭 시 해당 탭 비활성화 할지 여부")]
[SerializeField] private bool togglableTab = false;
// 탭 모델
private TabModel? _tabModel;
// 초기화 여부
private bool _isInitialized = false;
// 코드로 추가된 탭 설정 저장
private List<TabContentConfig> _additionalTabConfigs = new List<TabContentConfig>();
// 탭 변경 이벤트
public event Action<int>? OnTabChanged;
private void Awake()
{
_tabModel = new TabModel(togglableTab);
if (initializeOnStart)
{
Initialize();
}
}
#region
/// <summary>
/// 코드에서 탭 설정을 추가합니다.
/// </summary>
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;
}
/// <summary>
/// 모든 탭 설정을 가져옵니다.
/// </summary>
public List<TabContentConfig> GetAllTabConfigs()
{
List<TabContentConfig> allConfigs = new List<TabContentConfig>();
// 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
/// <summary>
/// 탭 시스템을 초기화합니다.
/// </summary>
public void Initialize()
{
if (_isInitialized || _tabModel == null || tabView == null)
return;
// 탭 모델 초기화
InitializeModel();
// TabView에 설정 전달하여 초기화
List<TabContentConfig> allConfigs = GetAllTabConfigs();
tabView.InitializeTabs(_tabModel.Tabs, allConfigs, OnTabButtonSelected, togglableTab);
// 모델 이벤트 구독
_tabModel.OnTabChanged += HandleTabChanged;
// 초기 탭 활성화
if (_tabModel.Tabs.Count > 0)
{
HandleTabChanged(_tabModel.ActiveTabIndex);
}
_isInitialized = true;
}
/// <summary>
/// 탭 모델을 초기화합니다.
/// </summary>
private void InitializeModel()
{
if (_tabModel == null) return;
List<TabContentConfig> allConfigs = GetAllTabConfigs();
foreach (var config in allConfigs)
{
_tabModel.AddTab(new TabData(
config.tabID,
config.tabName,
config.contentPath,
config.tabIconPath,
config.initialData
));
}
}
/// <summary>
/// 탭 버튼 선택 이벤트 처리
/// </summary>
private void OnTabButtonSelected(int tabIndex)
{
_tabModel?.SwitchToTab(tabIndex);
}
/// <summary>
/// 탭 변경 이벤트 처리
/// </summary>
private void HandleTabChanged(int newTabIndex, object? updateData = null)
{
if (_tabModel == null || tabView == null) return;
TabData? activeTabData = null;
if (newTabIndex > -1)
{
activeTabData = _tabModel.GetActiveTab();
if (activeTabData == null) return;
}
// TabView에 탭 변경 전달
tabView.UpdateActiveTab(newTabIndex, _tabModel.PrevTabIndex, activeTabData, updateData).ContinueWith(() =>
{
// 외부 이벤트 발생
OnTabChanged?.Invoke(newTabIndex);
});
}
#endregion
#region
/// <summary>
/// ID로 특정 탭을 활성화합니다.
/// </summary>
/// <param name="tabID">활성화할 탭의 ID</param>
/// <param name="updateData">탭에 전달할 데이터 (선택적)</param>
public void ActivateTab(string tabID, object? updateData = null)
{
_tabModel?.SwitchToTab(tabID, updateData);
}
/// <summary>
/// 인덱스로 특정 탭을 활성화합니다.
/// </summary>
/// <param name="tabIndex">활성화할 탭의 인덱스</param>
/// <param name="updateData">탭에 전달할 데이터 (선택적)</param>
public void ActivateTab(int tabIndex, object? updateData = null)
{
_tabModel?.SwitchToTab(tabIndex, updateData);
}
/// <summary>
/// 현재 활성화된 탭 인덱스를 반환합니다.
/// </summary>
public int GetActiveTabIndex()
{
return _tabModel?.ActiveTabIndex ?? -1;
}
/// <summary>
/// 현재 활성화된 탭의 ID를 반환합니다.
/// </summary>
public string? GetActiveTabID()
{
TabData? activeTab = _tabModel?.GetActiveTab();
return activeTab?.tabID;
}
/// <summary>
/// 현재 활성화된 탭의 ITabContent를 반환합니다.
/// </summary>
/// <returns>활성화된 탭의 ITabContent, 없으면 null</returns>
public ITabContent? GetActiveITabContent()
{
string? activeTabID = GetActiveTabID();
if (string.IsNullOrEmpty(activeTabID)) return null;
GameObject? tabInstance = GetTabInstance(activeTabID);
if (tabInstance == null) return null;
return tabInstance.GetComponent<ITabContent>();
}
/// <summary>
/// 특정 탭의 데이터를 설정하고 갱신합니다.
/// </summary>
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);
}
}
/// <summary>
/// 탭 ID로 인덱스를 찾습니다.
/// </summary>
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
/// <summary>
/// 특정 탭의 컨텐츠 인스턴스를 가져옵니다.
/// </summary>
public GameObject? GetTabInstance(string tabID, bool autoLoad = false)
{
return tabView?.GetTabInstance(tabID, autoLoad);
}
/// <summary>
/// 특정 탭의 컴포넌트를 가져옵니다.
/// </summary>
public T? GetTabComponent<T>(string tabID, bool autoLoad = false) where T : Component
{
return tabView?.GetTabComponent<T>(tabID, autoLoad);
}
/// <summary>
/// 특정 탭이 로드되었는지 확인합니다.
/// </summary>
public bool IsTabLoaded(string tabID)
{
return tabView?.IsTabLoaded(tabID) ?? false;
}
/// <summary>
/// 현재 활성화된 탭을 제외한 모든 지연 로드 탭을 언로드합니다.
/// </summary>
public void UnloadAllExceptCurrent()
{
int currentIndex = GetActiveTabIndex();
tabView?.UnloadAllExceptCurrent(currentIndex);
}
/// <summary>
/// 특정 탭의 컨텐츠를 언로드합니다.
/// </summary>
public bool UnloadTabContent(string tabID)
{
return tabView?.UnloadTabContent(tabID) ?? false;
}
/// <summary>
/// 모든 탭 컨텐츠를 미리 로드합니다.
/// </summary>
public void PreloadAllTabs()
{
tabView?.PreloadAllTabs();
}
#endregion
private void OnDestroy()
{
if (_tabModel != null)
{
_tabModel.OnTabChanged -= HandleTabChanged;
}
}
}
}