사용자 정보 표시 관리 팝업 완료

This commit is contained in:
logonkhi
2025-08-01 13:30:58 +09:00
parent 23da311db0
commit 22794651f2
16 changed files with 226 additions and 59 deletions

View File

@@ -1,5 +1,7 @@
using Cysharp.Threading.Tasks;
using SampleProject.Config; using SampleProject.Config;
using System; using System;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UVC.Core; using UVC.Core;
using UVC.Data; using UVC.Data;
@@ -20,9 +22,9 @@ namespace SampleProject
/// 초기 화 메서드입니다. /// 초기 화 메서드입니다.
/// Awake 메서드에서 호출되며, MonoBehaviour가 생성될 때 한 번만 실행됩니다. /// Awake 메서드에서 호출되며, MonoBehaviour가 생성될 때 한 번만 실행됩니다.
/// </summary> /// </summary>
protected override void Init() protected override async void Init()
{ {
SettupConfig(); await SettupConfigAsync();
SetNetworkConfig(); SetNetworkConfig();
if (Initialized != null) if (Initialized != null)
{ {
@@ -35,7 +37,7 @@ namespace SampleProject
//Tester.RunAllTests(); //Tester.RunAllTests();
} }
private void SettupConfig() private async UniTask SettupConfigAsync()
{ {
if (AppConfig.LoadConfig()) if (AppConfig.LoadConfig())
{ {
@@ -53,6 +55,10 @@ namespace SampleProject
} }
} }
} }
//사용자 DataMask 설정 AppData에서 로드
await DataMask.LoadUserMasksFromAppData();
} }
private void SetNetworkConfig() private void SetNetworkConfig()
@@ -82,7 +88,7 @@ namespace SampleProject
agvDataMask["JOB_ID"] = ""; agvDataMask["JOB_ID"] = "";
agvDataMask["TIMESTAMP"] = DateTime.Now; agvDataMask["TIMESTAMP"] = DateTime.Now;
DataMask.AddMask("AGV", agvDataMask); DataMask.AddMask("AGV", agvDataMask, true);
DataMapperValidator.Add("AGV", new DataMapperValidator( DataMapperValidator.Add("AGV", new DataMapperValidator(
new DataMapper(agvDataMask) new DataMapper(agvDataMask)
@@ -91,7 +97,7 @@ namespace SampleProject
// 데이터 마스크(DataMask) 정의: // 데이터 마스크(DataMask) 정의:
// 수신할 데이터의 구조를 미리 정의합니다. 여기서 정의된 키(Key)들을 기준으로 데이터를 파싱합니다. // 수신할 데이터의 구조를 미리 정의합니다. 여기서 정의된 키(Key)들을 기준으로 데이터를 파싱합니다.
var alarmDataMask = new DataMask(); var alarmDataMask = new DataMask();
alarmDataMask.ObjectName = "Alarm"; // Alarm 객체의 이름을 설정합니다. alarmDataMask.ObjectName = "ALARM"; // Alarm 객체의 이름을 설정합니다.
alarmDataMask.ObjectIdKey = "ID"; // Alarm의 고유 식별자로 사용할 키를 설정합니다. alarmDataMask.ObjectIdKey = "ID"; // Alarm의 고유 식별자로 사용할 키를 설정합니다.
alarmDataMask["ID"] = ""; alarmDataMask["ID"] = "";
alarmDataMask["ALARM_TYPE"] = ""; alarmDataMask["ALARM_TYPE"] = "";
@@ -112,7 +118,7 @@ namespace SampleProject
alarmDataMask["UPDATE_TIME"] = DateTime.Now; alarmDataMask["UPDATE_TIME"] = DateTime.Now;
alarmDataMask["TIMESTAMP"] = DateTime.Now; alarmDataMask["TIMESTAMP"] = DateTime.Now;
DataMask.AddMask("ALARM", alarmDataMask); DataMask.AddMask("ALARM", alarmDataMask, true);
// 데이터 유효성 검사기(DataValidator) 설정: // 데이터 유효성 검사기(DataValidator) 설정:
// 수신된 데이터가 유효한지 검사하는 규칙을 추가합니다. // 수신된 데이터가 유효한지 검사하는 규칙을 추가합니다.

View File

@@ -1,11 +1,8 @@
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using System; using System;
using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UVC.Core; using UVC.Core;
using UVC.Data; using UVC.Data;
using UVC.Data.Core;
using UVC.Data.Http;
using UVC.Factory; using UVC.Factory;
using UVC.Factory.Alarm; using UVC.Factory.Alarm;
using UVC.Factory.Component; using UVC.Factory.Component;
@@ -31,8 +28,6 @@ namespace SampleProject
AppMain.Instance.Initialized += OnAppInitialized; AppMain.Instance.Initialized += OnAppInitialized;
} }
private async void OnAppInitialized() private async void OnAppInitialized()
{ {
@@ -62,7 +57,7 @@ namespace SampleProject
FactoryCameraController.Instance.Enable = true; FactoryCameraController.Instance.Enable = true;
} }
private async Task requestDataAsync() private async UniTask requestDataAsync()
{ {
Debug.Log("requestDataAsync"); Debug.Log("requestDataAsync");

View File

@@ -1,9 +1,13 @@
#nullable enable #nullable enable
using Cysharp.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine;
using UVC.Extention; using UVC.Extention;
namespace UVC.Data.Core namespace UVC.Data.Core
@@ -17,6 +21,8 @@ namespace UVC.Data.Core
/// DataMask는 주로 DataMapper 클래스와 함께 사용되어 서로 다른 JSON 형식 간의 /// DataMask는 주로 DataMapper 클래스와 함께 사용되어 서로 다른 JSON 형식 간의
/// 데이터 변환 및 매핑 규칙을 정의합니다. 기본 JSON 구조 외에도 추가 속성들을 /// 데이터 변환 및 매핑 규칙을 정의합니다. 기본 JSON 구조 외에도 추가 속성들을
/// 통해 매핑 과정에서 필요한 메타데이터를 제공합니다. /// 통해 매핑 과정에서 필요한 메타데이터를 제공합니다.
/// 또한 AppData 폴더(AppData/Company Name/Product Name)에서 JSON 파일을 로드하고 저장하는 기능을 제공하여,
/// 그 기능은 FactoryObject의 정보를 InfoWindow로 보여줄때 사용됩니다.
/// </remarks> /// </remarks>
/// <example> /// <example>
/// 기본 사용 예시: /// 기본 사용 예시:
@@ -58,6 +64,10 @@ namespace UVC.Data.Core
private static Dictionary<string, DataMask> _dataMasks = new Dictionary<string, DataMask>(); private static Dictionary<string, DataMask> _dataMasks = new Dictionary<string, DataMask>();
public static IReadOnlyDictionary<string, DataMask> DataMasks => _dataMasks; public static IReadOnlyDictionary<string, DataMask> DataMasks => _dataMasks;
// 사용자 데이터 마스크를 저장하는 컬렉션입니다.
private static Dictionary<string, DataMask> _userDataMasks = new Dictionary<string, DataMask>();
public static IReadOnlyDictionary<string, DataMask> UserDataMasks => _userDataMasks;
/// <summary> /// <summary>
/// 컬렉션에 데이터 마스크를 추가하고 지정된 키와 연결합니다. /// 컬렉션에 데이터 마스크를 추가하고 지정된 키와 연결합니다.
/// </summary> /// </summary>
@@ -65,10 +75,16 @@ namespace UVC.Data.Core
///</remarks> ///</remarks>
/// <param name="key">데이터 마스크에 연결할 키입니다. <see langword="null"/>이거나 비어 있을 수 없습니다.</param> /// <param name="key">데이터 마스크에 연결할 키입니다. <see langword="null"/>이거나 비어 있을 수 없습니다.</param>
/// <param name="mask">추가할 <see cref="DataMask"/>입니다. <see langword="null"/>일 수 없습니다.</param> /// <param name="mask">추가할 <see cref="DataMask"/>입니다. <see langword="null"/>일 수 없습니다.</param>
public static void AddMask(string key, DataMask mask) /// <param name="withUser">사용자 데이터 마스크도 함께 추가할지 여부를 지정합니다. 기본값은 false입니다.</param>
public static void AddMask(string key, DataMask mask, bool withUser = false)
{ {
if (string.IsNullOrEmpty(key) || mask == null) return; if (string.IsNullOrEmpty(key) || mask == null) return;
_dataMasks[key] = mask; _dataMasks[key] = mask;
if (withUser && !_userDataMasks.ContainsKey(key))
{
// 사용자 데이터 마스크로 시작하는 키는 _userDataMasks에 추가
AddUserMask(key, mask.CreateUserMask());
}
} }
/// <summary> /// <summary>
@@ -76,10 +92,16 @@ namespace UVC.Data.Core
/// </summary> /// </summary>
/// <remarks> <paramref name="key"/>가 null이거나 비어 있으면 메서드는 아무 작업도 수행하지 않습니다.</remarks> /// <remarks> <paramref name="key"/>가 null이거나 비어 있으면 메서드는 아무 작업도 수행하지 않습니다.</remarks>
/// <param name="key">제거할 데이터 마스크를 식별하는 키입니다. null이거나 비어 있으면 안 됩니다.</param> /// <param name="key">제거할 데이터 마스크를 식별하는 키입니다. null이거나 비어 있으면 안 됩니다.</param>
public static void RemoveMask(string key) /// <param name="withUser">사용자 데이터 마스크도 함께 제거할지 여부를 지정합니다. 기본값은 false입니다.</param>
public static void RemoveMask(string key, bool withUser = false)
{ {
if (string.IsNullOrEmpty(key)) return; if (string.IsNullOrEmpty(key)) return;
_dataMasks.Remove(key); _dataMasks.Remove(key);
if(withUser)
{
// 사용자 데이터 마스크로 시작하는 키는 _userDataMasks에서 제거
RemoveUserMask(key);
}
} }
/// <summary> /// <summary>
@@ -95,7 +117,127 @@ namespace UVC.Data.Core
return mask; return mask;
} }
/// <summary>
/// 내부 컬렉션에서 모든 데이터 마스크를 지웁니다.
/// </summary>
/// <remarks>이 메서드는 내부 데이터 마스크 컬렉션에서 모든 항목을 제거하고
/// 빈 상태로 재설정합니다. 이전에 추가된 모든 마스크를 지워야 할 때 이 메서드를 사용하세요.</remarks>
public static void ClearMask()
{
_dataMasks.Clear();
}
/// <summary>
/// 사용자 정의 키를 지정된 데이터 마스크에 연결합니다.
/// </summary>
/// <remarks>동일한 키를 가진 데이터 마스크가 이미 있는 경우 새
/// 마스크로 대체됩니다.</remarks>
/// <param name="key">데이터 마스크의 고유 식별자입니다. <see langword="null"/>이거나 비어 있을 수 없습니다.</param>
/// <param name="mask">지정된 키와 연결할 <see cref="DataMask"/> 객체입니다. <see langword="null"/>일 수 없습니다.</param>
public static void AddUserMask(string key, DataMask mask)
{
if (string.IsNullOrEmpty(key) || mask == null) return;
_userDataMasks[key] = mask;
}
/// <summary>
/// 지정된 키와 연관된 사용자 마스크를 제거합니다.
/// </summary>
/// <remarks> <paramref name="key"/>가 null이거나 비어 있으면 메서드는 아무 작업도 수행하지 않습니다.
///</remarks>
/// <param name="key">제거할 사용자 마스크를 식별하는 키입니다. null이거나 비어 있으면 안 됩니다.</param>
public static void RemoveUserMask(string key)
{
if (string.IsNullOrEmpty(key)) return;
_userDataMasks.Remove(key);
}
/// <summary>
/// 지정된 키와 연관된 <see cref="DataMask"/>를 검색합니다.
/// </summary>
/// <param name="key">연관된 <see cref="DataMask"/>를 찾는 데 사용되는 키입니다. null이거나 비어 있을 수 없습니다.</param>
/// <returns>지정된 키와 연관된 <see cref="DataMask"/> 또는 키를 찾을 수 없거나 null이거나 비어 있는 경우 <see langword="null"/>을 반환합니다.
///</returns>
public static DataMask? GetUserMask(string key)
{
if (string.IsNullOrEmpty(key)) return null;
_userDataMasks.TryGetValue(key, out var mask);
return mask;
}
/// <summary>
/// 내부 컬렉션에서 모든 사용자 데이터 마스크를 지웁니다.
/// </summary>
/// <remarks>이 메서드는 사용자 데이터 마스크 컬렉션에서 모든 항목을 제거하고 빈 상태로 재설정합니다.
/// 일반적으로 새 마스크를 적용하기 전에 이전에 적용된 마스크를 지우는 데 사용됩니다.
///</remarks>
public static void ClearUserMask()
{
_userDataMasks.Clear();
}
/// <summary>
/// 애플리케이션의 영구 데이터 디렉터리(AppData/Company Name/Product Name)에서 사용자 마스크 데이터를 로드합니다.
/// </summary>
/// <remarks>이 메서드는 애플리케이션의 영구 데이터 경로에 있는 "user" 하위 디렉터리에서 JSON 파일을 검색합니다.
/// 각 JSON 파일을 읽고 그 내용을 사용하여 <see cref="DataMask"/>
/// 객체를 생성한 후 애플리케이션의 사용자 마스크 컬렉션에 추가합니다. 이 메서드는 메인 스레드를 차단하지 않도록 백그라운드
/// 스레드에서 실행됩니다.</remarks>
/// <returns></returns>
public static async UniTask LoadUserMasksFromAppData()
{
string persistentDataPath = UnityEngine.Application.persistentDataPath;
await UniTask.RunOnThreadPool(() =>
{
string folderPath = System.IO.Path.Combine(persistentDataPath, "user");
DirectoryInfo directory = new DirectoryInfo(folderPath);
if (!directory.Exists) return;
FileInfo[] files = directory.GetFiles("*.json");
foreach (FileInfo file in files)
{
string filePath = file.FullName;
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
if (string.IsNullOrEmpty(fileName)) continue;
string jsonString = System.IO.File.ReadAllText(filePath);
AddUserMask(fileName, new DataMask(jsonString));
}
});
}
/// <summary>
/// 사용자 데이터 마스크를 애플리케이션의 영구 데이터 경로(AppData/Company Name/Product Name)에 저장합니다.
/// </summary>
/// <remarks>이 메서드는 모든 사용자 데이터 마스크를 반복하며 각 마스크를 JSON 파일로 저장합니다.
/// 애플리케이션의 영구 데이터 경로에 있는 "user" 하위 디렉터리에 디렉터리가 없으면
/// 생성됩니다. 각 파일의 이름은 해당 키와 ".json" 확장자를 사용하여 지정됩니다. 저장 과정에서 발생하는 모든 오류는
/// Unity 콘솔에 기록됩니다.</remarks>
/// <returns></returns>
public static async UniTask SaveUserMasksToAppData()
{
string persistentDataPath = UnityEngine.Application.persistentDataPath;
await UniTask.RunOnThreadPool(() =>
{
foreach (var keyValue in _userDataMasks)
{
string key = keyValue.Key;
if (string.IsNullOrEmpty(key)) continue;
if (!_userDataMasks.TryGetValue(key, out var mask)) return;
try
{
string folderPath = System.IO.Path.Combine(persistentDataPath, "user");
if (!Directory.Exists(folderPath)) Directory.CreateDirectory(folderPath);
string filePath = System.IO.Path.Combine(folderPath, $"{key}.json");
string jsonString = mask.ToJsonString();
System.IO.File.WriteAllText(filePath, jsonString);
}
catch (Exception ex)
{
Debug.LogError($"DataMask SaveToStreamingAssets Error: {ex.Message}");
}
}
});
}
/// <summary> /// <summary>
/// DataObject의 Id에 해당하는 key 문자열입니다. /// DataObject의 Id에 해당하는 key 문자열입니다.
@@ -354,6 +496,23 @@ namespace UVC.Data.Core
return mask; return mask;
} }
/// <summary>
/// 현재 컬렉션의 각 키가 자기 자신에게 매핑되는 새로운 <see cref="DataMask"/> 인스턴스를 생성합니다.
/// </summary>
/// <remarks>이 메서드는 현재 컬렉션을 반복하고 컬렉션의 각 키가 결과 마스크의 키와 값으로 모두 사용되는 새로운 <see
/// cref="DataMask"/>를 생성합니다.
///</remarks>
/// <returns>각 키가 자기 자신에게 매핑되는 키-값 쌍을 포함하는 <see cref="DataMask"/> 객체를 반환합니다.</returns>
public DataMask CreateUserMask()
{
DataMask userMask = new DataMask();
foreach (var pair in this)
{
userMask[pair.Key] = pair.Key;
}
return userMask;
}
/// <summary> /// <summary>
/// Json 문자열로 변환합니다. /// Json 문자열로 변환합니다.
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using TMPro; #nullable enable
using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UVC.Data.Core; using UVC.Data.Core;
@@ -36,12 +37,24 @@ namespace UVC.Factory.Alarm
public void Show(DataObject data) public void Show(DataObject data)
{ {
string combinedString = string.Empty; string combinedString = string.Empty;
combinedString += $"ALARM_TYPE<indent=40%>{data.GetString("ALARM_TYPE") ?? "null"}</indent>\n"; DataMask? userMask = DataMask.GetUserMask("UserALARM");
combinedString += $"CODE<indent=40%>{data.GetString("CODE") ?? "null"}</indent>\n"; if (userMask != null)
combinedString += $"MACHINENAME<indent=40%>{data.GetString("MACHINENAME") ?? "null"}</indent>\n"; {
combinedString += $"MESSAGE<indent=40%>{data.GetString("MESSAGE") ?? "null"}</indent>\n"; foreach (var item in userMask)
combinedString += $"TIMESTAMP<indent=40%>{data.GetString("TIMESTAMP") ?? "null"}</indent>\n"; {
// DataObject에서 해당 키의 값을 가져와서 표시합니다.
combinedString += $"{item.Key}<indent=40%>{data.GetString(item.Key) ?? "null"}</indent>\n";
}
}
else
{
combinedString += $"ALARM_TYPE<indent=40%>{data.GetString("ALARM_TYPE") ?? "null"}</indent>\n";
combinedString += $"CODE<indent=40%>{data.GetString("CODE") ?? "null"}</indent>\n";
combinedString += $"MACHINENAME<indent=40%>{data.GetString("MACHINENAME") ?? "null"}</indent>\n";
combinedString += $"MESSAGE<indent=40%>{data.GetString("MESSAGE") ?? "null"}</indent>\n";
combinedString += $"TIMESTAMP<indent=40%>{data.GetString("TIMESTAMP") ?? "null"}</indent>\n";
}
combinedString = combinedString.TrimEnd('\n'); // 마지막 줄바꿈 제거 combinedString = combinedString.TrimEnd('\n'); // 마지막 줄바꿈 제거
detailTxt.text = combinedString; detailTxt.text = combinedString;

View File

@@ -72,8 +72,8 @@ namespace UVC.Factory.Component
public override void OnPointerClick(PointerEventData eventData) public override void OnPointerClick(PointerEventData eventData)
{ {
// 사용자가 AGV를 클릭했을 때 정보창에 표시될 데이터 항목과 순서를 정의합니다. // 사용자가 AGV를 클릭했을 때 정보창에 표시될 데이터 항목과 순서를 정의합니다. User+TOPIC 이름
DataOrderedMask = DataMask.Get("ConfigAGV"); if(dataOrderedMask == null) dataOrderedMask = DataMask.GetUserMask("AGV");
base.OnPointerClick(eventData); base.OnPointerClick(eventData);
} }

View File

@@ -24,6 +24,7 @@ namespace UVC.Factory.Modal.Config
var dic = DataMask.DataMasks; var dic = DataMask.DataMasks;
foreach (var item in dic) foreach (var item in dic)
{ {
if(item.Key.StartsWith("User")) continue; // "User"로 시작하지 않는 키만 처리합니다.
Debug.Log($"Key: {item.Key}, Value: {item.Value}"); Debug.Log($"Key: {item.Key}, Value: {item.Value}");
// 1. TabConfig 설정 // 1. TabConfig 설정
tabController.AddTabConfig(item.Key, item.Key, "Prefabs/UI/Tab/ConfigDataOrderTabContent", null, item.Key, true); tabController.AddTabConfig(item.Key, item.Key, "Prefabs/UI/Tab/ConfigDataOrderTabContent", null, item.Key, true);
@@ -49,7 +50,7 @@ namespace UVC.Factory.Modal.Config
/// </summary> /// </summary>
public override async UniTask OnClose(ModalContent content) public override async UniTask OnClose(ModalContent content)
{ {
await DataMask.SaveUserMasksToAppData(); // 데이터 마스크를 앱 데이터에 저장합니다.
await base.OnClose(content); await base.OnClose(content);
} }

View File

@@ -1,8 +1,8 @@
#nullable enable #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor.Rendering.LookDev;
using UnityEngine; using UnityEngine;
using UVC.Data.Core; using UVC.Data.Core;
using UVC.Extention;
using UVC.UI.List.Draggable; using UVC.UI.List.Draggable;
using UVC.UI.Tab; using UVC.UI.Tab;
@@ -15,7 +15,6 @@ namespace UVC.Factory.Modal.Config
private DraggableList? draggableList; private DraggableList? draggableList;
private string key = string.Empty; private string key = string.Empty;
private string configKey = string.Empty;
private DataMask? totalData = null; private DataMask? totalData = null;
private DataMask? viewData = null; private DataMask? viewData = null;
@@ -36,18 +35,15 @@ namespace UVC.Factory.Modal.Config
if (data is string key) if (data is string key)
{ {
this.key = key; this.key = key;
configKey = $"Config{key}"; totalData = DataMask.Get(key);
DataMask? mask = DataMask.Get(key);
if (mask != null) totalData = mask;
viewData = DataMask.Get(configKey);
if (totalData != null) if (totalData != null)
{ {
viewData = DataMask.GetUserMask(key);
//저장 되 있는 데이터가 없으면 전체 아이템을 체크된 상태로 추가 //저장 되 있는 데이터가 없으면 전체 아이템을 체크된 상태로 추가
if (viewData == null) if (viewData == null)
{ {
viewData = totalData.DeepClone(); viewData = totalData.CreateUserMask();
DataMask.AddMask(configKey, viewData); DataMask.AddUserMask(key, viewData);
} }
List<ConfigDataOrderListItemData> dataList = new List<ConfigDataOrderListItemData>(); List<ConfigDataOrderListItemData> dataList = new List<ConfigDataOrderListItemData>();
@@ -55,7 +51,7 @@ namespace UVC.Factory.Modal.Config
foreach (var item in totalData) foreach (var item in totalData)
{ {
bool isChecked = viewData!.ContainsKey(item.Key); bool isChecked = viewData!.ContainsKey(item.Key);
dataList.Add(new ConfigDataOrderListItemData(item.Key, item.Key, isChecked)); dataList.Add(new ConfigDataOrderListItemData(item.Key, (isChecked ? viewData[item.Key].ToString() : item.Key), isChecked));
} }
//드래그 가능한 리스트에 데이터 설정 //드래그 가능한 리스트에 데이터 설정
draggableList?.SetData<ConfigDataOrderListItemData>(dataList); draggableList?.SetData<ConfigDataOrderListItemData>(dataList);
@@ -76,9 +72,10 @@ namespace UVC.Factory.Modal.Config
private void UpdateData() private void UpdateData()
{ {
Debug.Log($"UpdateData: draggableList != null:{draggableList != null}, viewData != null:{viewData != null}, configKey:{configKey}"); Debug.Log($"UpdateData: draggableList != null:{draggableList != null}, viewData != null:{viewData != null}, configKey:{key}");
if (draggableList != null && viewData != null && configKey.Length > 0) if (draggableList != null && viewData != null && key.Length > 0)
{ {
viewData.Clear();
foreach (var item in draggableList.DataList) foreach (var item in draggableList.DataList)
{ {
if (item is ConfigDataOrderListItemData listItemData) if (item is ConfigDataOrderListItemData listItemData)
@@ -87,14 +84,10 @@ namespace UVC.Factory.Modal.Config
{ {
viewData[listItemData.Id] = listItemData.DisplayName; viewData[listItemData.Id] = listItemData.DisplayName;
} }
else
{
viewData.Remove(listItemData.Id);
}
} }
} }
Debug.Log($"UpdateData: {configKey} - {viewData.ToJsonString()} items"); Debug.Log($"UpdateData: {key} - {viewData.ToJsonString()} items");
DataMask.AddMask(configKey, viewData); DataMask.AddUserMask(key, viewData);
} }
} }

View File

@@ -194,7 +194,7 @@ namespace UVC.Factory.Playback
/// await PlaybackService.Instance.StartAsync(itemData); /// await PlaybackService.Instance.StartAsync(itemData);
/// </code> /// </code>
/// </example> /// </example>
public async Task StartAsync(UIPlaybackListItemData data) public async UniTask StartAsync(UIPlaybackListItemData data)
{ {
timeScale = 1.0f; //기본 시간 스케일 설정 timeScale = 1.0f; //기본 시간 스케일 설정
UIPlayback.Instance.Show(); UIPlayback.Instance.Show();

View File

@@ -123,7 +123,7 @@ namespace UVC.UI.List.Draggable
// 구독자들에게 드래그 종료를 알립니다 // 구독자들에게 드래그 종료를 알립니다
OnDragEnded?.Invoke(eventData); OnDragEnded?.Invoke(eventData);
Debug.Log($"[DragBehavior] 드래그 종료 - 아이템: {dragTarget.name}"); //Debug.Log($"[DragBehavior] 드래그 종료 - 아이템: {dragTarget.name}");
} }
/// <summary> /// <summary>
@@ -135,7 +135,7 @@ namespace UVC.UI.List.Draggable
originalIndex = dragTarget.GetSiblingIndex(); originalIndex = dragTarget.GetSiblingIndex();
originalPosition = dragTarget.position; originalPosition = dragTarget.position;
Debug.Log($"[DragBehavior] 위치 정보 업데이트 - 새 인덱스: {originalIndex}"); //Debug.Log($"[DragBehavior] 위치 정보 업데이트 - 새 인덱스: {originalIndex}");
} }
/// <summary> /// <summary>

View File

@@ -141,7 +141,7 @@ namespace UVC.UI.List.Draggable
if (reorderHandler == null) if (reorderHandler == null)
{ {
reorderHandler = content.gameObject.AddComponent<ListReorderHandler>(); reorderHandler = content.gameObject.AddComponent<ListReorderHandler>();
Debug.Log("[DraggableList] ListReorderHandler를 자동으로 추가했습니다."); //Debug.Log("[DraggableList] ListReorderHandler를 자동으로 추가했습니다.");
} }
// ScrollRectHandler 추가 또는 가져오기 // ScrollRectHandler 추가 또는 가져오기
@@ -152,7 +152,7 @@ namespace UVC.UI.List.Draggable
if (scrollHandler == null) if (scrollHandler == null)
{ {
scrollHandler = scrollRect.gameObject.AddComponent<ScrollRectHandler>(); scrollHandler = scrollRect.gameObject.AddComponent<ScrollRectHandler>();
Debug.Log("[DraggableList] ScrollRectHandler를 자동으로 추가했습니다."); //Debug.Log("[DraggableList] ScrollRectHandler를 자동으로 추가했습니다.");
} }
} }
@@ -249,6 +249,7 @@ namespace UVC.UI.List.Draggable
var item = dataList[oldIndex]; var item = dataList[oldIndex];
dataList.RemoveAt(oldIndex); dataList.RemoveAt(oldIndex);
dataList.Insert(newIndex, item); dataList.Insert(newIndex, item);
Debug.Log($"[DraggableList] 순서 변경: {oldIndex} -> {newIndex}");
// 이벤트 발생 // 이벤트 발생
OnOrderChanged?.Invoke((item as ListItemData)!, oldIndex, newIndex); OnOrderChanged?.Invoke((item as ListItemData)!, oldIndex, newIndex);
@@ -259,7 +260,6 @@ namespace UVC.UI.List.Draggable
// SaveOrder(); // SaveOrder();
//} //}
Debug.Log($"[DraggableList] 순서 변경: {oldIndex} -> {newIndex}");
} }
} }
@@ -269,7 +269,7 @@ namespace UVC.UI.List.Draggable
private void HandleItemClick(object data) private void HandleItemClick(object data)
{ {
OnItemClicked?.Invoke((data as ListItemData)!); OnItemClicked?.Invoke((data as ListItemData)!);
Debug.Log($"[DraggableList] 아이템 클릭: {(data as ListItemData)?.DisplayName}"); //Debug.Log($"[DraggableList] 아이템 클릭: {(data as ListItemData)?.DisplayName}");
} }
/// <summary> /// <summary>

View File

@@ -135,7 +135,7 @@ namespace UVC.UI.List.Draggable
/// </summary> /// </summary>
private void HandleDragEnd(PointerEventData eventData) private void HandleDragEnd(PointerEventData eventData)
{ {
Debug.Log($"[ListItemController] 드래그 종료 처리 - {gameObject.name}"); //Debug.Log($"[ListItemController] 드래그 종료 처리 - {gameObject.name}");
// 1. 아이템을 원래 투명도로 복원합니다 // 1. 아이템을 원래 투명도로 복원합니다
if (canvasGroup != null) if (canvasGroup != null)

View File

@@ -48,7 +48,7 @@ namespace UVC.UI.List.Draggable
boundData = data; boundData = data;
UpdateUI(); UpdateUI();
Debug.Log($"[ListItemView] 데이터 바인딩 완료 - {gameObject.name}"); //Debug.Log($"[ListItemView] 데이터 바인딩 완료 - {gameObject.name}");
} }
/// <summary> /// <summary>

View File

@@ -76,7 +76,7 @@ namespace UVC.UI.List.Draggable
// 마우스 위치에서 가장 가까운 인덱스를 계산합니다 // 마우스 위치에서 가장 가까운 인덱스를 계산합니다
int targetIndex = CalculateTargetIndex(position); int targetIndex = CalculateTargetIndex(position);
Debug.Log($"[ListReorderHandler] 드래그 위치 업데이트 - 타겟 인덱스: {targetIndex}"); //Debug.Log($"[ListReorderHandler] 드래그 위치 업데이트 - 타겟 인덱스: {targetIndex}");
if (targetIndex >= 0) if (targetIndex >= 0)
{ {
// 현재 플레이스홀더의 인덱스와 다를 때만 이동 // 현재 플레이스홀더의 인덱스와 다를 때만 이동
@@ -116,7 +116,7 @@ namespace UVC.UI.List.Draggable
if (item.OriginalIndex != newIndex) if (item.OriginalIndex != newIndex)
{ {
OnOrderChanged?.Invoke(item.OriginalIndex, newIndex); OnOrderChanged?.Invoke(item.OriginalIndex, newIndex);
Debug.Log($"[ListReorderHandler] 순서 변경됨: {item.OriginalIndex} -> {newIndex}"); //Debug.Log($"[ListReorderHandler] 순서 변경됨: {item.OriginalIndex} -> {newIndex}");
} }
} }
else else

View File

@@ -73,7 +73,7 @@ namespace UVC.UI.List.Draggable
if (autoScrollCoroutine == null) if (autoScrollCoroutine == null)
{ {
autoScrollCoroutine = StartCoroutine(AutoScrollRoutine()); autoScrollCoroutine = StartCoroutine(AutoScrollRoutine());
Debug.Log("[ScrollRectHandler] 자동 스크롤 시작"); //Debug.Log("[ScrollRectHandler] 자동 스크롤 시작");
} }
} }
else else
@@ -86,7 +86,7 @@ namespace UVC.UI.List.Draggable
{ {
StopCoroutine(autoScrollCoroutine); StopCoroutine(autoScrollCoroutine);
autoScrollCoroutine = null; autoScrollCoroutine = null;
Debug.Log("[ScrollRectHandler] 자동 스크롤 중지"); //Debug.Log("[ScrollRectHandler] 자동 스크롤 중지");
} }
} }
} }
@@ -123,7 +123,7 @@ namespace UVC.UI.List.Draggable
float normalizedDistance = (topY - mouseY) / scrollZoneHeight; float normalizedDistance = (topY - mouseY) / scrollZoneHeight;
scrollDelta = scrollSpeed * (1f - normalizedDistance) * Time.deltaTime; scrollDelta = scrollSpeed * (1f - normalizedDistance) * Time.deltaTime;
Debug.Log($"[ScrollRectHandler] 위로 스크롤 중... 속도: {scrollDelta}"); //Debug.Log($"[ScrollRectHandler] 위로 스크롤 중... 속도: {scrollDelta}");
} }
// 마우스가 아래쪽 가장자리 근처에 있으면 아래로 스크롤 // 마우스가 아래쪽 가장자리 근처에 있으면 아래로 스크롤
else if (mouseY < bottomY + scrollZoneHeight && mouseY >= bottomY) else if (mouseY < bottomY + scrollZoneHeight && mouseY >= bottomY)
@@ -132,7 +132,7 @@ namespace UVC.UI.List.Draggable
float normalizedDistance = (mouseY - bottomY) / scrollZoneHeight; float normalizedDistance = (mouseY - bottomY) / scrollZoneHeight;
scrollDelta = -scrollSpeed * (1f - normalizedDistance) * Time.deltaTime; scrollDelta = -scrollSpeed * (1f - normalizedDistance) * Time.deltaTime;
Debug.Log($"[ScrollRectHandler] 아래로 스크롤 중... 속도: {scrollDelta}"); //Debug.Log($"[ScrollRectHandler] 아래로 스크롤 중... 속도: {scrollDelta}");
} }
// 스크롤 적용 // 스크롤 적용

View File

@@ -136,7 +136,6 @@ namespace UVC.UI.Loading
{ {
// 이미 애니메이션이 진행 중이고, 목표가 '나타나기(target=1)'라면 중복 실행을 방지합니다. // 이미 애니메이션이 진행 중이고, 목표가 '나타나기(target=1)'라면 중복 실행을 방지합니다.
if (animatting && target == 1) return; if (animatting && target == 1) return;
target = 1; // 목표 알파 값을 1(불투명)로 설정 target = 1; // 목표 알파 값을 1(불투명)로 설정
animatting = true; // 애니메이션 시작 상태로 변경 animatting = true; // 애니메이션 시작 상태로 변경
StopCoroutine("Animate"); // 이전에 실행 중이던 Animate 코루틴이 있다면 중지 StopCoroutine("Animate"); // 이전에 실행 중이던 Animate 코루틴이 있다면 중지

View File

@@ -6,6 +6,7 @@ namespace UVC.UI.Modal
/// <summary> /// <summary>
/// 📜 모달 창에 어떤 내용을 보여줄지, 어떻게 행동할지 정하는 '레시피' 또는 '주문서' 같은 친구예요. /// 📜 모달 창에 어떤 내용을 보여줄지, 어떻게 행동할지 정하는 '레시피' 또는 '주문서' 같은 친구예요.
/// 이 클래스의 객체를 만들어서 Modal.Open()에 전달하면, 여기에 적힌 대로 모달 창이 만들어져요. /// 이 클래스의 객체를 만들어서 Modal.Open()에 전달하면, 여기에 적힌 대로 모달 창이 만들어져요.
/// 커스텀 모달 창을 만들 때는 ModalView를 상속받아서 Prefab으로 만들고 ModalContent 생성자에 Prefab 경로를 전달해야 한다.
/// </summary> /// </summary>
/// <example> /// <example>
/// <code> /// <code>