Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/PDA/Chat/AppChat.cs
2025-06-24 23:49:13 +08:00

293 lines
9.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net.Http;
using System.Text;
using BITKit;
using BITKit.StateMachine;
using BITKit.UX;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Net.BITKit.Chat;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.UIElements;
namespace Net.Project.B.PDA.App
{
[Serializable]
public struct Chat : IApp
{
public string PackageName => "com.bndroid.chat";
public string AppName => "聊天";
}
public class AppChat : PDAApp<Chat>
{
private readonly IChatService _chatService;
private readonly IServiceProvider _serviceProvider;
protected override string DocumentPath => "ui_app_chat";
[UXBindPath("chat-panel")] private VisualElement _chatPanel;
[UXBindPath("chat_list-container")] private VisualElement _chatListContainer;
[UXBindPath("chat-container")] private VisualElement _chatContainer;
[UXBindPath("message-field")] private TextField _messageField;
[UXBindPath("send-button")] private Button _sendButton;
[UXBindPath("chat-scroll")] private ScrollView _chatScroll;
[UXBindPath("chat_user-label")] private Label _chatUserLabel;
[UXBindPath("is_typing-label")] private Label _isTypingLabel;
private VisualTreeAsset _chatTemplate;
private VisualTreeAsset _chatListTemplate;
private readonly ValidHandle _userTyping = new();
private readonly Dictionary<string, VisualElement> _chatList = new();
private string _currentUserId = string.Empty;
public AppChat(IServiceProvider serviceProvider, IChatService chatService)
{
_serviceProvider = serviceProvider;
_chatService = chatService;
}
public override void Initialize()
{
base.Initialize();
_chatTemplate = _chatContainer.Q<TemplateContainer>().templateSource;
_chatListTemplate = _chatListContainer.Q<TemplateContainer>().templateSource;
_messageField.RegisterValueChangedCallback(x =>
_sendButton.SetActive(string.IsNullOrEmpty(x.newValue) is false));
_sendButton.clicked += SendMessage;
_messageField.value = string.Empty;
_messageField.BlinkingCursor();
_messageField.RegisterCallback<KeyDownEvent>(OnKeyDown);
_userTyping.AddListener(_isTypingLabel.SetActive);
_userTyping.Invoke();
_chatListContainer.Clear()
;
_chatContainer.Clear();
_chatService.OnMessageReceived += OnMessageReceived;
_chatPanel.SetActive(false);
}
private void OnMessageReceived(ChatMessage obj)
{
if (obj.FromUserId != Environment.UserName && obj.ToUserId != Environment.UserName) return;
_serviceProvider.GetRequiredService<IPDAService>().Badge(App.PackageName);
var chatList = GetOrCreateChatList(obj);
if (obj.FromUserId != _currentUserId && obj.ToUserId != _currentUserId)
{
chatList.AddToClassList("allow-badge");
return;
}
CreateMessage(obj);
}
public override async UniTask OnStateEntryAsync(IState old)
{
await base.OnStateEntryAsync(old);
_chatListContainer.Clear();
_chatList.Clear();
foreach (var chatMessage in await _chatService.GetChatList(Environment.UserName))
{
GetOrCreateChatList(chatMessage);
}
}
private VisualElement GetOrCreateChatList(ChatMessage chatMessage)
{
var userName = string.Equals(chatMessage.FromUserId, Environment.UserName)
? chatMessage.ToUserId
: chatMessage.FromUserId;
if (_chatList.TryGetValue(userName, out var container))
{
container.Get<Label>().text = $"{userName} at{chatMessage.Timestamp:HH:mm}";
container.Get<Label>(1).text = chatMessage.Content.Split("\n").First();
return container;
}
container = _chatList[userName] = _chatListContainer.Create(_chatListTemplate);
container.viewDataKey = userName;
container.Get<Label>().text = userName;
container.Get<Label>(1).text = chatMessage.Content;
container.Get<Label>(2).text = userName[0].ToString();
container.Get<Button>().clicked += () => Chat(userName);
_chatList[userName] = container;
return container;
}
private async void Chat(string userId)
{
_chatUserLabel.text = _currentUserId = userId;
foreach (var visualElement in _chatListContainer.Children())
{
if (visualElement.viewDataKey == userId)
{
visualElement.AddToClassList("selected");
visualElement.RemoveFromClassList("allow-badge");
}
else
{
visualElement.RemoveFromClassList("selected");
}
}
_chatContainer.Clear();
foreach (var chatMessage in await _chatService.GetMessages(Environment.UserName, userId))
{
CreateMessage(chatMessage);
}
_chatScroll.ScrollToBottom();
_userTyping.RemoveElement(this);
_chatPanel.SetActive(true);
}
private void CreateMessage(ChatMessage chatMessage)
{
var container = _chatContainer.Create(_chatTemplate);
container.Get<Label>().text = chatMessage.Content;
container.Get<Label>(1).text =$"{chatMessage.FromUserId} at{chatMessage.Timestamp:HH:mm}";
container.Get<Label>(2).text = chatMessage.ToUserId[0].ToString();
if (!string.Equals(chatMessage.FromUserId, Environment.UserName)) return;
container.Get<Label>(2).text = chatMessage.FromUserId[0].ToString();
container.AddToClassList("self");
}
private void OnKeyDown(KeyDownEvent keyDownEvent)
{
switch (keyDownEvent.keyCode)
{
case KeyCode.Return:
SendMessage();
keyDownEvent.StopPropagation();
keyDownEvent.PreventDefault();
break;
}
}
private async void SendMessage()
{
try
{
var message = _messageField.value;
if (string.IsNullOrEmpty(message)) return;
_userTyping.AddElement(this);
_messageField.value = "";
var currentUserId = _currentUserId;
await _chatService.SendMessage(new ChatMessage
{
FromUserId = Environment.UserName,
ToUserId = currentUserId,
Content = message,
});
//_chatScroll.verticalScroller.value = _chatScroll.verticalScroller.highValue;
_chatScroll.ScrollToBottom();
//_chatScroll.ScrollToBottomAutomatic();
using var client = new HttpClient();
string url =
"http://server.bitfall.icu:18918/api/application/chat_message/ceb19752-185e-11f0-9541-0242ac120009";
dynamic data = new ExpandoObject() { };
data.message = message;
data.re_chat = false;
data.stream = false;
// 构造 JSON 数据
var json = JsonConvert.SerializeObject(data);
// 设置请求体
var content = new StringContent(json, Encoding.UTF8, "application/json");
// 添加请求头
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("AUTHORIZATION", "application-012e89878ee3e8dcfc4bc59a0c5648ae");
client.DefaultRequestHeaders.Add("accept", "application/json");
// 发送请求
var response = await client.PostAsync(url, content);
string newMessage;
try
{
response.EnsureSuccessStatusCode();
// 处理返回
json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<dynamic>(json);
newMessage = result.data.content;
}
catch (Exception e)
{
Debug.LogException(e);
newMessage = e.Message;
}
await _chatService.SendMessage(new ChatMessage()
{
FromUserId = currentUserId,
ToUserId = Environment.UserName,
Content = newMessage
});
if (_currentUserId != currentUserId) return;
await UniTask.NextFrame();
_chatScroll.ScrollToBottom();
}
finally
{
_userTyping.RemoveElement(this);
}
}
}
}