UI HUGE UPDATE
This commit is contained in:
@@ -8,6 +8,8 @@ using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
using Bansonic;
|
||||
|
||||
public class globalChatSystem : MonoBehaviour
|
||||
{
|
||||
private enum ChatChannelMode
|
||||
@@ -37,6 +39,9 @@ public class globalChatSystem : MonoBehaviour
|
||||
public GameObject worldSystemMessagePrefab;
|
||||
public Transform playerMessageParent;
|
||||
|
||||
[Header("extra")]
|
||||
public Button emojiButton;
|
||||
|
||||
[Header("send")]
|
||||
public InputField messageInputField;
|
||||
public Button sendButton;
|
||||
@@ -55,6 +60,8 @@ public class globalChatSystem : MonoBehaviour
|
||||
|
||||
[SerializeField] Text channelNameText;
|
||||
[SerializeField] Button back_to_worldwideChatButton;
|
||||
[SerializeField] Toggle globalChatToggle;
|
||||
[SerializeField] Toggle friendChatToggle;
|
||||
|
||||
private ArenaRoomService _service;
|
||||
private ScrollRect _scrollRect;
|
||||
@@ -75,6 +82,7 @@ public class globalChatSystem : MonoBehaviour
|
||||
private long _nextFeedSequence = 1;
|
||||
private ChatChannelMode _currentMode = ChatChannelMode.World;
|
||||
private string _currentPrivatePartnerId;
|
||||
private string _lastPrivatePartnerId = string.Empty;
|
||||
private string _defaultChannelName = string.Empty;
|
||||
private static string _pendingPrivatePartnerId;
|
||||
private Coroutine _layoutRefreshCoroutine;
|
||||
@@ -83,7 +91,11 @@ public class globalChatSystem : MonoBehaviour
|
||||
private readonly List<RectTransform> _pendingLayoutDirtyRoots = new List<RectTransform>();
|
||||
private Coroutine _refocusInputCoroutine;
|
||||
private bool _refocusInputRequested;
|
||||
private bool _suppressModeToggleEvents;
|
||||
private bool _modeTogglesAutoCreated;
|
||||
private ToggleGroup _chatModeToggleGroup;
|
||||
public static globalChatSystem Instance { get; private set; }
|
||||
public static event Action<string> ActivePrivateConversationChanged;
|
||||
|
||||
private const float WorldChatSendCooldownSeconds = 10f;
|
||||
private const float PrivateChatSendCooldownSeconds = 1f;
|
||||
@@ -93,6 +105,9 @@ public class globalChatSystem : MonoBehaviour
|
||||
private const string DefaultWorldChannelName = "世界聊天";
|
||||
private const string CooldownPlaceholderFormat = "\u53d1\u9001\u51b7\u5374\u4e2d {0}s";
|
||||
private const string PrivateChannelNameFormat = "\u6b63\u5728\u4e0e[{0}]\u79c1\u804a";
|
||||
private const string DefaultFriendChannelName = "\u597d\u53cb\u804a\u5929";
|
||||
private const string NoRecentPrivateConversationNotice = "\u6682\u65e0\u6700\u8fd1\u79c1\u804a\u5bf9\u8c61";
|
||||
private const string LastPrivatePartnerPrefKey = "global_chat_last_private_partner_id";
|
||||
|
||||
public static void OpenPrivateConversation(string steamId)
|
||||
{
|
||||
@@ -132,6 +147,7 @@ public class globalChatSystem : MonoBehaviour
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
_lastPrivatePartnerId = PlayerPrefs.GetString(LastPrivatePartnerPrefKey, string.Empty);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -182,6 +198,8 @@ public class globalChatSystem : MonoBehaviour
|
||||
back_to_worldwideChatButton.onClick.AddListener(HandleBackToWorldClicked);
|
||||
}
|
||||
|
||||
EnsureChatModeToggles();
|
||||
|
||||
if (_service != null)
|
||||
{
|
||||
_service.SetWorldChatCacheLimit(GetEffectiveCacheLimit());
|
||||
@@ -211,6 +229,8 @@ public class globalChatSystem : MonoBehaviour
|
||||
ClearDisplayedMessages();
|
||||
_isViewPinnedToBottom = true;
|
||||
_windowStartIndex = -1;
|
||||
EnsureChatModeToggles();
|
||||
NotifyActivePrivateConversationChanged();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_pendingPrivatePartnerId))
|
||||
{
|
||||
@@ -237,6 +257,8 @@ public class globalChatSystem : MonoBehaviour
|
||||
_scrollRect.onValueChanged.RemoveListener(OnScrollValueChanged);
|
||||
}
|
||||
|
||||
UnbindChatModeToggleListeners();
|
||||
|
||||
if (_chatCooldownRoutine != null)
|
||||
{
|
||||
StopCoroutine(_chatCooldownRoutine);
|
||||
@@ -256,6 +278,7 @@ public class globalChatSystem : MonoBehaviour
|
||||
}
|
||||
|
||||
RestoreDefaultPlaceholder();
|
||||
NotifyActivePrivateConversationChanged();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@@ -270,6 +293,8 @@ public class globalChatSystem : MonoBehaviour
|
||||
back_to_worldwideChatButton.onClick.RemoveListener(HandleBackToWorldClicked);
|
||||
}
|
||||
|
||||
UnbindChatModeToggleListeners();
|
||||
|
||||
if (sendButton != null)
|
||||
{
|
||||
sendButton.onClick.RemoveListener(OnSendClicked);
|
||||
@@ -365,6 +390,7 @@ public class globalChatSystem : MonoBehaviour
|
||||
_currentPrivatePartnerId = null;
|
||||
ResetFeedForChannelSwitch();
|
||||
ApplyChannelHeader();
|
||||
NotifyActivePrivateConversationChanged();
|
||||
await _service.EnsureWorldChatConnected();
|
||||
await _service.LoadWorldHistory(InitialHistoryLoadLimit);
|
||||
RenderMessages(_service.GetWorldChatMessages(), false);
|
||||
@@ -379,8 +405,10 @@ public class globalChatSystem : MonoBehaviour
|
||||
|
||||
_currentMode = ChatChannelMode.Private;
|
||||
_currentPrivatePartnerId = partnerId.Trim();
|
||||
RememberPrivatePartner(_currentPrivatePartnerId);
|
||||
ResetFeedForChannelSwitch();
|
||||
ApplyChannelHeader();
|
||||
NotifyActivePrivateConversationChanged();
|
||||
await _service.LoadPrivateHistory(_currentPrivatePartnerId, InitialHistoryLoadLimit);
|
||||
RenderMessages(_service.GetPrivateChatMessages(_currentPrivatePartnerId), false);
|
||||
}
|
||||
@@ -394,10 +422,17 @@ public class globalChatSystem : MonoBehaviour
|
||||
{
|
||||
if (back_to_worldwideChatButton != null)
|
||||
{
|
||||
back_to_worldwideChatButton.gameObject.SetActive(_currentMode == ChatChannelMode.Private);
|
||||
back_to_worldwideChatButton.gameObject.SetActive(_currentMode == ChatChannelMode.Private && !HasChatModeToggles());
|
||||
}
|
||||
|
||||
if (channelNameText == null)
|
||||
if (_modeTogglesAutoCreated && channelNameText != null)
|
||||
{
|
||||
channelNameText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
UpdateChatModeToggleVisuals();
|
||||
|
||||
if (channelNameText == null || _modeTogglesAutoCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -1168,6 +1203,318 @@ public class globalChatSystem : MonoBehaviour
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public static bool IsViewingPrivateConversation(string steamId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(steamId) || Instance == null || !Instance.isActiveAndEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Instance._currentMode == ChatChannelMode.Private
|
||||
&& string.Equals(Instance._currentPrivatePartnerId, steamId.Trim(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private void EnsureChatModeToggles()
|
||||
{
|
||||
if (globalChatToggle == null || friendChatToggle == null)
|
||||
{
|
||||
CreateFallbackChatModeToggles();
|
||||
}
|
||||
|
||||
BindChatModeToggleListeners();
|
||||
UpdateChatModeToggleVisuals();
|
||||
}
|
||||
|
||||
private void BindChatModeToggleListeners()
|
||||
{
|
||||
if (globalChatToggle != null)
|
||||
{
|
||||
globalChatToggle.onValueChanged.RemoveListener(HandleGlobalChatToggleChanged);
|
||||
globalChatToggle.onValueChanged.AddListener(HandleGlobalChatToggleChanged);
|
||||
}
|
||||
|
||||
if (friendChatToggle != null)
|
||||
{
|
||||
friendChatToggle.onValueChanged.RemoveListener(HandleFriendChatToggleChanged);
|
||||
friendChatToggle.onValueChanged.AddListener(HandleFriendChatToggleChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnbindChatModeToggleListeners()
|
||||
{
|
||||
if (globalChatToggle != null)
|
||||
{
|
||||
globalChatToggle.onValueChanged.RemoveListener(HandleGlobalChatToggleChanged);
|
||||
}
|
||||
|
||||
if (friendChatToggle != null)
|
||||
{
|
||||
friendChatToggle.onValueChanged.RemoveListener(HandleFriendChatToggleChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGlobalChatToggleChanged(bool isOn)
|
||||
{
|
||||
if (_suppressModeToggleEvents || !isOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = SwitchToWorldChannelAsync();
|
||||
}
|
||||
|
||||
private void HandleFriendChatToggleChanged(bool isOn)
|
||||
{
|
||||
if (_suppressModeToggleEvents || !isOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OpenRecentPrivateConversationFromToggle();
|
||||
}
|
||||
|
||||
private async void OpenRecentPrivateConversationFromToggle()
|
||||
{
|
||||
string partnerId = ResolvePreferredPrivatePartnerId();
|
||||
if (string.IsNullOrWhiteSpace(partnerId))
|
||||
{
|
||||
AddSystemMessage(NoRecentPrivateConversationNotice);
|
||||
UpdateChatModeToggleVisuals();
|
||||
return;
|
||||
}
|
||||
|
||||
await SwitchToPrivateChannelAsync(partnerId);
|
||||
}
|
||||
|
||||
private void UpdateChatModeToggleVisuals()
|
||||
{
|
||||
if (globalChatToggle != null)
|
||||
{
|
||||
SetToggleWithoutNotify(globalChatToggle, _currentMode == ChatChannelMode.World);
|
||||
}
|
||||
|
||||
if (friendChatToggle != null)
|
||||
{
|
||||
SetToggleWithoutNotify(friendChatToggle, _currentMode == ChatChannelMode.Private);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void SetToggleWithoutNotify(Toggle toggle, bool value)
|
||||
{
|
||||
if (toggle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_suppressModeToggleEvents = true;
|
||||
toggle.SetIsOnWithoutNotify(value);
|
||||
_suppressModeToggleEvents = false;
|
||||
}
|
||||
|
||||
private bool HasChatModeToggles()
|
||||
{
|
||||
return globalChatToggle != null && friendChatToggle != null;
|
||||
}
|
||||
|
||||
private void CreateFallbackChatModeToggles()
|
||||
{
|
||||
if (globalChatToggle != null && friendChatToggle != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RectTransform headerRect = channelNameText != null ? channelNameText.rectTransform.parent as RectTransform : null;
|
||||
if (headerRect == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelNameText != null)
|
||||
{
|
||||
channelNameText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
headerRect.sizeDelta = new Vector2(360f, 34f);
|
||||
|
||||
if (_chatModeToggleGroup == null)
|
||||
{
|
||||
_chatModeToggleGroup = headerRect.GetComponent<ToggleGroup>();
|
||||
if (_chatModeToggleGroup == null)
|
||||
{
|
||||
_chatModeToggleGroup = headerRect.gameObject.AddComponent<ToggleGroup>();
|
||||
}
|
||||
_chatModeToggleGroup.allowSwitchOff = false;
|
||||
}
|
||||
|
||||
if (globalChatToggle == null)
|
||||
{
|
||||
globalChatToggle = CreateRuntimeModeToggle(headerRect, "globalChatToggle", DefaultWorldChannelName, new Vector2(-90f, 0f));
|
||||
}
|
||||
|
||||
if (friendChatToggle == null)
|
||||
{
|
||||
friendChatToggle = CreateRuntimeModeToggle(headerRect, "friendChatToggle", DefaultFriendChannelName, new Vector2(90f, 0f));
|
||||
}
|
||||
|
||||
if (globalChatToggle != null)
|
||||
{
|
||||
globalChatToggle.group = _chatModeToggleGroup;
|
||||
}
|
||||
|
||||
if (friendChatToggle != null)
|
||||
{
|
||||
friendChatToggle.group = _chatModeToggleGroup;
|
||||
}
|
||||
|
||||
_modeTogglesAutoCreated = globalChatToggle != null && friendChatToggle != null;
|
||||
}
|
||||
|
||||
private Toggle CreateRuntimeModeToggle(RectTransform parent, string objectName, string labelText, Vector2 anchoredPosition)
|
||||
{
|
||||
Sprite defaultSprite = Resources.GetBuiltinResource<Sprite>("UISprite.psd");
|
||||
Font defaultFont = channelNameText != null && channelNameText.font != null
|
||||
? channelNameText.font
|
||||
: Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
|
||||
GameObject toggleObject = new GameObject(objectName, typeof(RectTransform), typeof(Image), typeof(Toggle));
|
||||
RectTransform toggleRect = toggleObject.GetComponent<RectTransform>();
|
||||
toggleRect.SetParent(parent, false);
|
||||
toggleRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
toggleRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
toggleRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
toggleRect.anchoredPosition = anchoredPosition;
|
||||
toggleRect.sizeDelta = new Vector2(164f, 30f);
|
||||
|
||||
Image background = toggleObject.GetComponent<Image>();
|
||||
background.sprite = defaultSprite;
|
||||
background.type = Image.Type.Sliced;
|
||||
background.color = new Color(1f, 1f, 1f, 0.32f);
|
||||
|
||||
Toggle toggle = toggleObject.GetComponent<Toggle>();
|
||||
toggle.targetGraphic = background;
|
||||
toggle.transition = Selectable.Transition.ColorTint;
|
||||
|
||||
ColorBlock colors = toggle.colors;
|
||||
colors.normalColor = new Color(1f, 1f, 1f, 0.45f);
|
||||
colors.highlightedColor = new Color(1f, 1f, 1f, 0.55f);
|
||||
colors.pressedColor = new Color(0.86f, 0.94f, 1f, 0.85f);
|
||||
colors.selectedColor = new Color(0.86f, 0.94f, 1f, 0.95f);
|
||||
colors.disabledColor = new Color(1f, 1f, 1f, 0.2f);
|
||||
toggle.colors = colors;
|
||||
|
||||
GameObject checkmarkObject = new GameObject("Checkmark", typeof(RectTransform), typeof(Image));
|
||||
RectTransform checkmarkRect = checkmarkObject.GetComponent<RectTransform>();
|
||||
checkmarkRect.SetParent(toggleRect, false);
|
||||
checkmarkRect.anchorMin = Vector2.zero;
|
||||
checkmarkRect.anchorMax = Vector2.one;
|
||||
checkmarkRect.offsetMin = new Vector2(3f, 3f);
|
||||
checkmarkRect.offsetMax = new Vector2(-3f, -3f);
|
||||
|
||||
Image checkmark = checkmarkObject.GetComponent<Image>();
|
||||
checkmark.sprite = defaultSprite;
|
||||
checkmark.type = Image.Type.Sliced;
|
||||
checkmark.color = new Color(0.63f, 0.87f, 1f, 0.95f);
|
||||
toggle.graphic = checkmark;
|
||||
|
||||
GameObject labelObject = new GameObject("Label", typeof(RectTransform), typeof(Text));
|
||||
RectTransform labelRect = labelObject.GetComponent<RectTransform>();
|
||||
labelRect.SetParent(toggleRect, false);
|
||||
labelRect.anchorMin = Vector2.zero;
|
||||
labelRect.anchorMax = Vector2.one;
|
||||
labelRect.offsetMin = new Vector2(10f, 0f);
|
||||
labelRect.offsetMax = new Vector2(-10f, 0f);
|
||||
|
||||
Text label = labelObject.GetComponent<Text>();
|
||||
label.font = defaultFont;
|
||||
label.fontSize = 16;
|
||||
label.alignment = TextAnchor.MiddleCenter;
|
||||
label.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||
label.verticalOverflow = VerticalWrapMode.Overflow;
|
||||
label.color = new Color(0.19607843f, 0.19607843f, 0.19607843f, 1f);
|
||||
label.text = labelText;
|
||||
|
||||
return toggle;
|
||||
}
|
||||
|
||||
private void RememberPrivatePartner(string partnerId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(partnerId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastPrivatePartnerId = partnerId.Trim();
|
||||
PlayerPrefs.SetString(LastPrivatePartnerPrefKey, _lastPrivatePartnerId);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
private string ResolvePreferredPrivatePartnerId()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_lastPrivatePartnerId))
|
||||
{
|
||||
return _lastPrivatePartnerId;
|
||||
}
|
||||
|
||||
if (TryGetMostRecentPrivatePartnerId(out string recentPartnerId))
|
||||
{
|
||||
return recentPartnerId;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private bool TryGetMostRecentPrivatePartnerId(out string partnerId)
|
||||
{
|
||||
partnerId = string.Empty;
|
||||
if (_service == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string bestPartner = string.Empty;
|
||||
long bestTimestamp = long.MinValue;
|
||||
|
||||
foreach (SocialFriendEntry friend in _service.GetFriendsSnapshot())
|
||||
{
|
||||
string candidateId = friend != null ? friend.friend_steam_id : string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(candidateId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IReadOnlyList<ArenaRoomChatMessage> messages = _service.GetPrivateChatMessages(candidateId);
|
||||
if (messages == null || messages.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ArenaRoomChatMessage lastMessage = messages[messages.Count - 1];
|
||||
long timestamp = ParseMessageUnixTimestamp(lastMessage != null ? lastMessage.created_at : string.Empty);
|
||||
if (timestamp > bestTimestamp)
|
||||
{
|
||||
bestTimestamp = timestamp;
|
||||
bestPartner = candidateId;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(bestPartner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
partnerId = bestPartner;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void NotifyActivePrivateConversationChanged()
|
||||
{
|
||||
string activePartnerId = isActiveAndEnabled && _currentMode == ChatChannelMode.Private
|
||||
? _currentPrivatePartnerId ?? string.Empty
|
||||
: string.Empty;
|
||||
ActivePrivateConversationChanged?.Invoke(activePartnerId);
|
||||
}
|
||||
|
||||
private int GetEffectiveCacheLimit()
|
||||
{
|
||||
return Mathf.Max(InitialHistoryLoadLimit, Mathf.Max(1, maxMessageHistory));
|
||||
|
||||
Reference in New Issue
Block a user