using BrewMonster.Network; using NUnit.Framework; using System; using System.Collections.Generic; using TMPro; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; public class ShopDetailPanel : MonoBehaviour { [Header("UI Components")] public TextMeshProUGUI itemNameText; public TextMeshProUGUI itemDescriptionText; public Image itemIconImage; public TextMeshProUGUI itemPriceText; public TextMeshProUGUI itemQuantityText; public TextMeshProUGUI itemGiftText; [Header("Buy Options")] public Button[] buyOptionButtons; // Up to 4 buy options public TextMeshProUGUI[] buyOptionPriceTexts; public TextMeshProUGUI[] buyOptionStatusTexts; [Header("Action Buttons")] public Button buyButton; public Button closeButton; private GShopItem currentItem; private ShopUIManager shopManager; void Start() { SetupEventListeners(); } void SetupEventListeners() { if (buyButton != null) buyButton.onClick.AddListener(OnBuyClicked); if (closeButton != null) closeButton.onClick.AddListener(OnCloseClicked); // Setup buy option buttons for (int i = 0; i < buyOptionButtons.Length; i++) { int optionIndex = i; // Capture for closure if (buyOptionButtons[i] != null) { buyOptionButtons[i].onClick.AddListener(() => OnBuyOptionSelected(optionIndex)); } } } public void SetupDetailPanel(GShopItem item, ShopUIManager manager) { Debug.Log($"[ShopDetailPanel] SetupDetailPanel called with item ID: {item.id}, Name: '{item.name}', Icon: '{item.icon}'"); currentItem = item; shopManager = manager; UpdateDisplay(); } void UpdateDisplay() { Debug.Log($"[ShopDetailPanel] UpdateDisplay called for item ID: {currentItem.id}"); if (currentItem.id == 0) { Debug.LogWarning("[ShopDetailPanel] Current item ID is 0, skipping display update"); return; } // Set basic item info if (itemNameText != null) itemNameText.text = currentItem.name; if (itemDescriptionText != null) { RemoveCaretColor(itemDescriptionText.text = ConvertColorCodeOfText(currentItem.desc)); } if (itemQuantityText != null) itemQuantityText.text = $"Quantity: {currentItem.num}"; // Load icon Debug.Log($"[ShopDetailPanel] About to load icon. itemIconImage is null: {itemIconImage == null}"); Debug.Log($"[ShopDetailPanel] Current item icon field: '{currentItem.icon}'"); if (itemPriceText != null) { itemPriceText.text = currentItem.buy[0].price.ToString(); LayoutRebuilder.ForceRebuildLayoutImmediate(itemPriceText.transform as RectTransform); } if (itemIconImage != null) { LoadItemIcon(itemIconImage, currentItem.icon); } else { Debug.LogError("[ShopDetailPanel] itemIconImage is null! Make sure it's assigned in the inspector."); } // Update buy options UpdateBuyOptions(); // Update gift info UpdateGiftInfo(); } struct ColorText { public string hex; public string content; } private string ConvertColorCodeOfText(string input) { /*string returnValue = ""; List colorTexts = new List(); ColorText currentColorText = new ColorText(); currentColorText.hex = "ffffff"; currentColorText.content = ""; for (int i = 0; i < input.Length; i++) { if (input[i] == '^' && i + 6 < input.Length) { // Store the current segment before changing color colorTexts.Add(currentColorText); // Start a new color segment currentColorText = new ColorText(); currentColorText.hex = input.Substring(i + 1, 6); currentColorText.content = ""; i += 6; } else { currentColorText.content += input[i]; } } foreach ( var ct in colorTexts) { if (ct.hex.ToLower() != "ffffff") { returnValue += $"{ct.content}"; } else { returnValue += ct.content; } Debug.Log($"[ShopDetailPanel] Processed ColorText: Hex='{ct.hex}', Content='{ct.content}'"); } return returnValue;*/ if (string.IsNullOrEmpty(input)) return input; input = input.Replace("\\r\\n", "\n"); input = input.Replace("\\r", "\n"); input = input.Replace("\\n", "\n"); input = input.Replace("\r\n", "\n"); input = input.Replace("\r", "\n"); input = input.Replace("\n", "\n"); System.Text.StringBuilder sb = new System.Text. StringBuilder(); for (int i = 0; i < input.Length; i++) { if (input[i] == '^' && i + 6 < input.Length) { string hex = input.Substring(i + 1, 6); if (hex.ToLower() != "ffffff") { sb.Append($""); } i += 6; } else { sb.Append(input[i]); } } sb.Append(""); return sb.ToString(); } public static string RemoveCaretColor(string input) { return System.Text.RegularExpressions.Regex.Replace(input, @"\^[0-9a-fA-F]{6}", ""); } void UpdateBuyOptions() { for (int i = 0; i < buyOptionButtons.Length && i < currentItem.buy.Length; i++) { var buyOption = currentItem.buy[i]; // Show/hide buy option based on price bool hasValidPrice = buyOption.price > 0; if (buyOptionButtons[i] != null) { buyOptionButtons[i].gameObject.SetActive(hasValidPrice); } if (hasValidPrice) { // Set price text if (i < buyOptionPriceTexts.Length && buyOptionPriceTexts[i] != null) { buyOptionPriceTexts[i].text = buyOption.price.ToString(); } // Set status text if (i < buyOptionStatusTexts.Length && buyOptionStatusTexts[i] != null) { string statusText = GetStatusText(buyOption.status); buyOptionStatusTexts[i].text = statusText; } } } } string GetStatusText(uint status) { switch (status) { case 0: return ""; case 1: return "HOT"; case 2: return "NEW"; case 3: return "RECOMMENDED"; case 4: return "10% OFF"; case 5: return "20% OFF"; case 6: return "30% OFF"; case 7: return "40% OFF"; case 8: return "50% OFF"; case 9: return "60% OFF"; case 10: return "70% OFF"; case 11: return "80% OFF"; case 12: return "90% OFF"; case 13: return "SOLD OUT"; default: return ""; } } void UpdateGiftInfo() { if (itemGiftText != null) { if (currentItem.idGift > 0) { itemGiftText.text = $"Gift: {currentItem.giftNum}x (ID: {currentItem.idGift})"; itemGiftText.gameObject.SetActive(true); } else { itemGiftText.gameObject.SetActive(false); } } } void LoadItemIcon(Image iconImage, string itemIcon) { Debug.Log($"[ShopDetailPanel] LoadItemIcon called with itemIcon: '{itemIcon}'"); if (string.IsNullOrEmpty(itemIcon)) { Debug.LogWarning("[ShopDetailPanel] Item icon path is null or empty"); return; } // Extract filename from path (e.g., "surfaces/.../... .dds" -> "... .dds") string fileName = ExtractFileNameFromPath(itemIcon); Debug.Log($"[ShopDetailPanel] Extracted filename: '{fileName}' from path: '{itemIcon}'"); // Load sprite from DDSAtlas using the same system as inventory items Sprite iconSprite = LoadSpriteFromDDSAtlas(fileName); if (iconSprite != null) { iconImage.sprite = iconSprite; Debug.Log($"[ShopDetailPanel] Successfully loaded icon: {fileName}"); } else { Debug.LogWarning($"[ShopDetailPanel] Failed to load icon from DDSAtlas: {fileName}"); iconImage.sprite = null; } } private string ExtractFileNameFromPath(string iconPath) { if (string.IsNullOrEmpty(iconPath)) return string.Empty; try { // Replace backslashes with forward slashes for consistency string normalizedPath = iconPath.Replace('\\', '/'); // Get the filename from the path string fileName = System.IO.Path.GetFileName(normalizedPath); if (string.IsNullOrEmpty(fileName)) fileName = normalizedPath; // Remove extension (.dds/.tga/.png) to get the sprite name string spriteName = System.IO.Path.GetFileNameWithoutExtension(fileName); if (string.IsNullOrEmpty(spriteName)) spriteName = fileName; return spriteName.Trim(); } catch (System.Exception ex) { Debug.LogError($"Error extracting filename from path '{iconPath}': {ex.Message}"); return string.Empty; } } private Sprite LoadSpriteFromDDSAtlas(string spriteName) { Debug.Log($"[ShopDetailPanel] LoadSpriteFromDDSAtlas called with spriteName: '{spriteName}'"); if (string.IsNullOrEmpty(spriteName)) { Debug.LogWarning("[ShopDetailPanel] Sprite name is null or empty"); return null; } try { // Load the DDSAtlas sprites if not already loaded var atlasSprites = UnityEngine.Resources.LoadAll("UI/MallItemImg/DDSAtlas"); Debug.Log($"[ShopDetailPanel] Loaded {atlasSprites?.Length ?? 0} sprites from Resources/UI/MallItemImg/DDSAtlas"); if (atlasSprites == null || atlasSprites.Length == 0) { Debug.LogWarning("[ShopDetailPanel] Failed to load DDSAtlas sprites from Resources/UI/MallItemImg/DDSAtlas"); return null; } // Log first few sprite names for debugging for (int i = 0; i < Mathf.Min(5, atlasSprites.Length); i++) { if (atlasSprites[i] != null) { Debug.Log($"[ShopDetailPanel] Atlas sprite {i}: '{atlasSprites[i].name}'"); } } // Try to find sprite by exact name match (case insensitive) foreach (var sprite in atlasSprites) { if (sprite != null && string.Equals(sprite.name, spriteName, System.StringComparison.OrdinalIgnoreCase)) { Debug.Log($"[ShopDetailPanel] Found exact match for sprite: '{spriteName}'"); return sprite; } } // Try lowercase/uppercase variants as fallback foreach (var sprite in atlasSprites) { if (sprite != null && (string.Equals(sprite.name, spriteName.ToLowerInvariant(), System.StringComparison.OrdinalIgnoreCase) || string.Equals(sprite.name, spriteName.ToUpperInvariant(), System.StringComparison.OrdinalIgnoreCase))) { Debug.Log($"[ShopDetailPanel] Found case variant match for sprite: '{spriteName}'"); return sprite; } } Debug.LogWarning($"[ShopDetailPanel] Sprite '{spriteName}' not found in DDSAtlas. Available sprites: {string.Join(", ", System.Array.ConvertAll(atlasSprites, s => s?.name ?? "null"))}"); return null; } catch (System.Exception ex) { Debug.LogError($"[ShopDetailPanel] Error loading sprite '{spriteName}' from DDSAtlas: {ex.Message}"); return null; } } void OnBuyOptionSelected(int optionIndex) { if (currentItem.buy == null || optionIndex >= currentItem.buy.Length) return; var selectedOption = currentItem.buy[optionIndex]; if (selectedOption.price > 0 && selectedOption.status != 13) // Not sold out { // TODO: Implement purchase with specific buy option Debug.Log($"Selected buy option {optionIndex}: Price={selectedOption.price}, Status={selectedOption.status}"); // Update main price display if (itemPriceText != null) itemPriceText.text = $"Price: {selectedOption.price}"; } } void OnBuyClicked() { // TODO: Implement purchase logic Debug.Log($"Attempting to buy item: ID {currentItem.id} (Index: {currentItem.itemIndex})"); UnityGameSession.Instance.RequestMallShopping(1, Convert.ToInt32(currentItem.id), currentItem.itemIndex, 0); // Close panel after purchase attempt OnCloseClicked(); } void OnCloseClicked() { gameObject.SetActive(false); } void OnDestroy() { // Clean up event listeners if (buyButton != null) buyButton.onClick.RemoveListener(OnBuyClicked); if (closeButton != null) closeButton.onClick.RemoveListener(OnCloseClicked); for (int i = 0; i < buyOptionButtons.Length; i++) { if (buyOptionButtons[i] != null) { int optionIndex = i; // Capture for closure buyOptionButtons[i].onClick.RemoveListener(() => OnBuyOptionSelected(optionIndex)); } } } }