using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using UnityEngine.UI;
|
|
public class ChatWin : UIBase
|
{
|
[SerializeField, Header("锁定当前区域比例"), Range(0, 1)] float m_Percent = 0.3f;
|
[SerializeField] ButtonEx btnSetting;
|
[SerializeField] ButtonEx btnClose;
|
|
[SerializeField] ScrollerController scrChatTab;
|
[SerializeField] ChatPlayerMineCell m_ChatMineCell;
|
[SerializeField] ChatPlayerOtherCell m_ChatOtherCell;
|
[SerializeField] ChatSysCell m_ChatSysCell;
|
|
[SerializeField] Transform transInput;
|
[SerializeField] InputField inputChat;
|
[SerializeField] ButtonEx btnSendChat;
|
[SerializeField] ImageEx imgSendChat;
|
[SerializeField] TextEx txtSendChat;
|
[SerializeField] ScrollerController scrWorld;
|
[SerializeField] ScrollerController scrGuild;
|
|
private int unreadMsgCount = 0;
|
[SerializeField] ButtonEx btnNewMsgTip;
|
[SerializeField] TextEx txtNewMsgTip;
|
|
[SerializeField, Header("聊天弹幕设置")] Transform transSettings;
|
[SerializeField] ClickScreenOtherSpace clickScreenOtherSpace;
|
bool isSettingOpen = false;
|
[SerializeField] ChatSettingButton btnWorldSetting;
|
[SerializeField] ChatSettingButton btnGuildSetting;
|
ChatManager manager { get { return ChatManager.Instance; } }
|
|
protected override void InitComponent()
|
{
|
base.InitComponent();
|
btnClose.SetListener(CloseWindow);
|
btnSendChat.SetListener(() =>
|
{
|
// 如果在聊天输入界面无输入文字点击发送,则关闭聊天输入界面
|
if (string.IsNullOrEmpty(inputChat.text))
|
{
|
CloseWindow();
|
return;
|
}
|
|
if (!manager.CheckChatLimit(inputChat.text, out int errorCode))
|
{
|
manager.ShowChatErrorTip(errorCode);
|
return;
|
}
|
manager.SendChatInfo(manager.nowChatChannel, inputChat.text);
|
manager.AddChatChannelSendTime(manager.nowChatChannel, TimeUtility.AllSeconds);
|
inputChat.text = string.Empty;
|
UpdateSendButton();
|
});
|
btnNewMsgTip.SetListener(() =>
|
{
|
if (manager.nowChatChannel == ChatChannel.World)
|
{
|
RefreshChat(manager.nowChatChannel, scrWorld);
|
ScrollerJump(scrWorld, ChatChannel.World);
|
}
|
else if (manager.nowChatChannel == ChatChannel.Guild)
|
{
|
RefreshChat(manager.nowChatChannel, scrGuild);
|
ScrollerJump(scrGuild, ChatChannel.Guild);
|
}
|
ClearUnreadMsg();
|
});
|
btnSetting.SetListener(() =>
|
{
|
isSettingOpen = !isSettingOpen;
|
transSettings.SetActive(isSettingOpen);
|
});
|
|
}
|
|
// 清理未读消息状态
|
private void ClearUnreadMsg()
|
{
|
unreadMsgCount = 0;
|
btnNewMsgTip.SetActive(false);
|
}
|
|
// 更新未读消息UI
|
private void UpdateUnreadMsgUI()
|
{
|
btnNewMsgTip.SetActive(unreadMsgCount > 0);
|
txtNewMsgTip.text = Language.Get("Chat10", unreadMsgCount);
|
}
|
|
protected override void OnPreOpen()
|
{
|
base.OnPreOpen();
|
manager.OnChatTabChangeEvent += OnChatTabChange;
|
manager.OnUpdateTalkEvent += OnUpdateTalkEvent;
|
manager.OnUpdateTalkCacheListEvent += OnUpdateTalkCacheList;
|
|
scrChatTab.OnRefreshCell += OnRefreshChatTabCell;
|
scrWorld.OnGetDynamicSize += OnGetWorldChatDynamicSize;
|
scrWorld.OnRefreshCell += OnRefreshWorldCell;
|
scrWorld.mScrollRect.onValueChanged.AddListener(OnWorldScrollValChange);
|
scrGuild.OnGetDynamicSize += OnGetWorldChatDynamicSize;
|
scrGuild.OnRefreshCell += OnRefreshGuildCell;
|
scrGuild.mScrollRect.onValueChanged.AddListener(OnGuildScrollValChange);
|
|
clickScreenOtherSpace.AddListener(OnClickScreenOtherSpace);
|
GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
|
|
isSettingOpen = false;
|
transSettings.SetActive(isSettingOpen);
|
btnWorldSetting.SetChannelType(ChatChannel.World);
|
btnGuildSetting.SetChannelType(ChatChannel.Guild);
|
inputChat.characterLimit = ChatManager.Instance.characterLimit;
|
CreaterAll(manager.nowChatTab);
|
}
|
|
|
|
protected override void OnPreClose()
|
{
|
base.OnPreClose();
|
manager.OnChatTabChangeEvent -= OnChatTabChange;
|
manager.OnUpdateTalkEvent -= OnUpdateTalkEvent;
|
manager.OnUpdateTalkCacheListEvent -= OnUpdateTalkCacheList;
|
|
scrChatTab.OnRefreshCell -= OnRefreshChatTabCell;
|
scrWorld.OnGetDynamicSize -= OnGetWorldChatDynamicSize;
|
scrWorld.OnRefreshCell -= OnRefreshWorldCell;
|
scrWorld.mScrollRect.onValueChanged.RemoveListener(OnWorldScrollValChange);
|
scrGuild.OnGetDynamicSize -= OnGetGuildChatDynamicSize;
|
scrGuild.OnRefreshCell -= OnRefreshGuildCell;
|
scrGuild.mScrollRect.onValueChanged.RemoveListener(OnGuildScrollValChange);
|
GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
|
clickScreenOtherSpace.RemoveAllListeners();
|
}
|
|
private void OnRefreshGuildCell(ScrollerDataType type, CellView cell)
|
{
|
OnRefreshCell(type, cell);
|
}
|
|
private void OnRefreshWorldCell(ScrollerDataType type, CellView cell)
|
{
|
OnRefreshCell(type, cell);
|
}
|
private void OnRefreshCell(ScrollerDataType type, CellView cell)
|
{
|
if (type == ScrollerDataType.Header)
|
{
|
var _cell = cell.GetComponent<ChatPlayerMineCell>();
|
_cell?.Refresh(cell);
|
}
|
else if (type == ScrollerDataType.Normal)
|
{
|
var _cell = cell.GetComponent<ChatPlayerOtherCell>();
|
_cell?.Refresh(cell);
|
}
|
else if (type == ScrollerDataType.Tail)
|
{
|
var _cell = cell.GetComponent<ChatSysCell>();
|
_cell?.Refresh(cell);
|
}
|
else if (type == ScrollerDataType.Extra1)
|
{
|
var _cell = cell.GetComponent<ChatDateCell>();
|
_cell?.Refresh(cell);
|
}
|
}
|
|
private void OnSecondEvent()
|
{
|
UpdateSendButton();
|
}
|
|
private void OnClickScreenOtherSpace()
|
{
|
isSettingOpen = !isSettingOpen;
|
transSettings.SetActive(isSettingOpen);
|
}
|
|
private bool m_isJumpArea;
|
public bool isJumpArea
|
{
|
get { return m_isJumpArea; }
|
set
|
{
|
if (m_isJumpArea == value)
|
return;
|
m_isJumpArea = value;
|
|
// isJumpArea = true (用户在底部):开启锁定底部
|
if (value)
|
{
|
if (scrWorld.lockType != EnhanceLockType.LockVerticalBottom)
|
scrWorld.lockType = EnhanceLockType.LockVerticalBottom;
|
|
// 如果回到底部,直接清零消息
|
ClearUnreadMsg();
|
}
|
// isJumpArea = false (用户看历史):保持视觉位置
|
else
|
{
|
if (scrWorld.lockType != EnhanceLockType.KeepVertical)
|
scrWorld.lockType = EnhanceLockType.KeepVertical;
|
}
|
}
|
}
|
|
private void OnWorldScrollValChange(Vector2 _pos)
|
{
|
OnScrollValChange(scrWorld, _pos);
|
}
|
|
private void OnGuildScrollValChange(Vector2 _pos)
|
{
|
OnScrollValChange(scrGuild, _pos);
|
}
|
|
private void OnScrollValChange(ScrollerController scorller, Vector2 _pos)
|
{
|
if (scorller.m_Scorller._ScrollSize <= 0)
|
return;
|
|
float _value = m_Percent / scorller.m_Scorller._ScrollSize * scorller.m_Scorller.ScrollRectSize;
|
isJumpArea = _pos.y <= _value;
|
|
// 检查滚动位置是否覆盖了新消息
|
if (unreadMsgCount <= 0)
|
return;
|
int totalCount = scorller.GetNumberOfCells(scorller.m_Scorller);
|
int thresholdIndex = totalCount - unreadMsgCount;
|
|
// 获取当前视窗最底部显示的 Item 索引
|
int currentBottomIndex = scorller.m_Scorller.EndDataIndex;
|
// 如果当前看到的底部索引 超过了 新消息的起始线(减1是为了容错)
|
if (currentBottomIndex >= thresholdIndex - 1)
|
{
|
ClearUnreadMsg();
|
}
|
}
|
|
private void OnChatTabChange(ChatTab entrance)
|
{
|
CreaterAll(entrance);
|
}
|
|
private void OnUpdateTalkEvent(ChatChannel type, TalkData data)
|
{
|
RefreshAll(type, playerId: data.PlayerID);
|
}
|
|
private void OnUpdateTalkCacheList()
|
{
|
RefreshAll(manager.nowChatChannel);
|
}
|
|
private void CreaterAll(ChatTab chatTab)
|
{
|
if (chatTab == ChatTab.World)
|
{
|
manager.nowChatChannel = ChatChannel.World;
|
}
|
else if (chatTab == ChatTab.Guild)
|
{
|
manager.nowChatChannel = ChatChannel.Guild;
|
}
|
|
UpdateSendButton();
|
// 打开界面时默认到底部,无未读
|
isJumpArea = true;
|
scrWorld.lockType = EnhanceLockType.LockVerticalBottom; // 初始锁定底部
|
scrWorld.SetActive(chatTab == ChatTab.World);
|
|
scrGuild.lockType = EnhanceLockType.LockVerticalBottom; // 初始锁定底部
|
scrGuild.SetActive(chatTab == ChatTab.Guild);
|
|
transInput.SetActive(chatTab == ChatTab.World || chatTab == ChatTab.Guild);
|
|
CreateChatTabScroller();
|
|
switch (chatTab)
|
{
|
case ChatTab.World:
|
manager.nowChatChannel = ChatChannel.World;
|
CreateScroller(scrWorld, ChatChannel.World);
|
ScrollerJump(scrWorld, ChatChannel.World);
|
ClearUnreadMsg();
|
break;
|
case ChatTab.Guild:
|
manager.nowChatChannel = ChatChannel.Guild;
|
CreateScroller(scrGuild, ChatChannel.Guild);
|
ScrollerJump(scrGuild, ChatChannel.Guild);
|
ClearUnreadMsg();
|
break;
|
}
|
}
|
|
float KeepArea(ScrollerController scroller)
|
{
|
if (scroller.GetNumberOfCells(scroller.m_Scorller) >= manager.maxTalkCount)
|
{
|
float totalRemovedSize = 0f;
|
for (int i = 0; i < manager.deleteTalkCount; i++)
|
{
|
float cellSize = scroller.GetCellSize(i);
|
totalRemovedSize += cellSize + scroller.m_Scorller.spacing;
|
}
|
return totalRemovedSize;
|
}
|
return 0;
|
}
|
|
private void RefreshAll(ChatChannel type, uint playerId = 0)
|
{
|
scrChatTab.m_Scorller.RefreshActiveCellViews();
|
if (type == ChatChannel.World)
|
{
|
RefreshChat(type, scrWorld, playerId);
|
}
|
else if (type == ChatChannel.Guild)
|
{
|
RefreshChat(type, scrGuild, playerId);
|
}
|
|
}
|
|
private void RefreshChat(ChatChannel type, ScrollerController scroller, uint playerId = 0)
|
{
|
if (!manager.TryGetTalkData(type, out List<TalkData> datas) || datas == null)
|
return;
|
int numberOfCells = scroller.GetNumberOfCells(scroller.m_Scorller);
|
if (numberOfCells < manager.maxTalkCount)
|
{
|
for (int i = numberOfCells; i < datas.Count; i++)
|
{
|
|
TalkData data = datas[i];
|
ScrollerDataType scrollerDataType = GetCellType(data);
|
scroller.AddCell(scrollerDataType, i);
|
int talkDataType = manager.GetTalkDataType(data);
|
float height = GetHeight(talkDataType, data.Content, data.InfoList);
|
scroller.m_Scorller.AddHeight(true, height);
|
//Debug.Log($"ChatWin AddCell i {i} AddHeight {height}");
|
}
|
}
|
else
|
{
|
scroller.m_Scorller.RefreshActiveCellViews();
|
}
|
|
if (type == ChatChannel.World && manager.nowChatTab != ChatTab.World)
|
return;
|
if (type == ChatChannel.Guild && manager.nowChatTab != ChatTab.Guild)
|
return;
|
// 1. 自己发送的消息 -> 强制跳转到底部 + 清零
|
if (playerId == PlayerDatas.Instance.PlayerId)
|
{
|
isJumpArea = true;
|
scroller.lockType = EnhanceLockType.LockVerticalBottom;
|
ScrollerJump(scroller, type);
|
ClearUnreadMsg(); // 自己发的消息不用提示
|
}
|
// 2. 别人发消息 & 当前在底部 -> 自动跟随 + 清零
|
else if (isJumpArea)
|
{
|
scroller.lockType = EnhanceLockType.LockVerticalBottom;
|
ScrollerJump(scroller, type);
|
ClearUnreadMsg(); // 在底部看着不用提示
|
}
|
// 3. 别人发消息 & 当前在看历史 -> 保持位置 + 增加未读计数
|
else
|
{
|
scroller.lockType = EnhanceLockType.KeepVertical;
|
float offset = KeepArea(scroller);
|
if (Math.Abs(offset) > 0.001f)
|
{
|
ScrollerJump(scroller, offset);
|
}
|
|
if (type == manager.nowChatChannel)
|
{
|
unreadMsgCount++;
|
UpdateUnreadMsgUI();
|
}
|
|
// 特殊情况:如果未读数量巨大(超过了总显示数量),说明整个列表都被刷新了,直接消零
|
if (unreadMsgCount >= scrWorld.GetNumberOfCells(scrWorld.m_Scorller))
|
{
|
ClearUnreadMsg();
|
}
|
}
|
}
|
private bool OnGetWorldChatDynamicSize(ScrollerDataType _type, int _index, out float height)
|
{
|
return OnGetChatDynamicSize(_type, _index, out height);
|
}
|
|
private bool OnGetGuildChatDynamicSize(ScrollerDataType _type, int _index, out float height)
|
{
|
return OnGetChatDynamicSize(_type, _index, out height);
|
}
|
|
private bool OnGetChatDynamicSize(ScrollerDataType _type, int _index, out float height)
|
{
|
height = 0;
|
if (!manager.TryGetChatData(manager.nowChatChannel, _index, out TalkData data) || data == null)
|
return false;
|
switch (_type)
|
{
|
case ScrollerDataType.Header:
|
height = m_ChatMineCell.GetHeight(data.Content, data.InfoList);
|
return true;
|
case ScrollerDataType.Normal:
|
height = m_ChatOtherCell.GetHeight(data.Content, data.InfoList);
|
return true;
|
case ScrollerDataType.Tail:
|
height = m_ChatSysCell.GetHeight(data.Content, data.InfoList);
|
return true;
|
case ScrollerDataType.Extra1:
|
height = 30;
|
return true;
|
}
|
return true;
|
}
|
private void OnRefreshChatTabCell(ScrollerDataType type, CellView cell)
|
{
|
var _cell = cell.GetComponent<ChatTabCell>();
|
_cell?.Display(cell.index, cell);
|
}
|
|
private void CreateChatTabScroller()
|
{
|
scrChatTab.Refresh();
|
for (int i = 0; i < manager.tabShowList.Count; i++)
|
{
|
CellInfo cellInfo = new CellInfo();
|
cellInfo.infoInt1 = (int)manager.tabShowList[i];
|
scrChatTab.AddCell(ScrollerDataType.Header, i, cellInfo);
|
}
|
scrChatTab.Restart();
|
}
|
|
private void CreateScroller(ScrollerController scroller, ChatChannel type)
|
{
|
scroller.Refresh();
|
if (manager.TryGetTalkData(type, out List<TalkData> datas))
|
{
|
for (int i = 0; i < datas.Count; i++)
|
{
|
TalkData data = datas[i];
|
ScrollerDataType scrollerDataType = GetCellType(data);
|
scroller.AddCell(scrollerDataType, i);
|
}
|
}
|
scroller.Restart();
|
}
|
|
private void ScrollerJump(ScrollerController scroller, ChatChannel type)
|
{
|
scroller.lockType = EnhanceLockType.LockVerticalBottom;
|
scroller.ResetScrollPos();
|
int jumpIndex = manager.GetJumpIndex(type);
|
scroller.JumpIndex(jumpIndex);
|
//Debug.Log($"ChatWin JumpIndex {jumpIndex}");
|
isJumpArea = true;
|
}
|
|
|
private void ScrollerJump(ScrollerController scroller, float _offset)
|
{
|
scroller.JumpIndex(-_offset, 0, EnhancedUI.EnhancedScroller.EnhancedScroller.TweenType.immediate);
|
}
|
// 0-系统 1-日期 2-自己 3-其他玩家
|
private ScrollerDataType GetCellType(TalkData data)
|
{
|
int type = manager.GetTalkDataType(data);
|
if (type == 0)
|
return ScrollerDataType.Tail;
|
else if (type == 1)
|
return ScrollerDataType.Extra1;
|
else if (type == 2)
|
return ScrollerDataType.Header;
|
else
|
return ScrollerDataType.Normal;
|
}
|
public float GetHeight(int type, string content, ArrayList list)
|
{
|
switch (type)
|
{
|
case 0:
|
return m_ChatSysCell.GetHeight(content, list);
|
case 1:
|
return 30;
|
case 2:
|
return m_ChatMineCell.GetHeight(content, list);
|
case 3:
|
return m_ChatOtherCell.GetHeight(content, list);
|
}
|
return 0;
|
}
|
private void UpdateSendButton()
|
{
|
bool isCanSend = manager.IsCanSend(manager.nowChatChannel, out int remainingSeconds);
|
btnSendChat.interactable = isCanSend;
|
imgSendChat.gray = !isCanSend;
|
txtSendChat.text = isCanSend ? Language.Get("Chat02") : Language.Get("Chat14", remainingSeconds);
|
txtSendChat.colorType = isCanSend ? TextColType.NavyBrown : TextColType.LightWhite;
|
}
|
}
|