add gs
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
local Players = game:GetService("Players")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
local LuaChat = script.Parent.Parent
|
||||
local UserThumbnail = require(script.Parent.UserThumbnail)
|
||||
local TypingIndicator = require(script.Parent.TypingIndicator)
|
||||
|
||||
local UserChatBubble = require(script.Parent.UserChatBubble)
|
||||
local AssetCard = require(script.Parent.AssetCard)
|
||||
|
||||
local Create = require(LuaChat.Create)
|
||||
local Constants = require(LuaChat.Constants)
|
||||
local WebApi = require(LuaChat.WebApi)
|
||||
|
||||
local Modules = game:GetService("CoreGui").RobloxGui.Modules
|
||||
local LuaApp = Modules.LuaApp
|
||||
local NotificationType = require(LuaApp.Enum.NotificationType)
|
||||
|
||||
local FFlagLuaChatToSplitRbxConnections = settings():GetFFlag("LuaChatToSplitRbxConnections")
|
||||
|
||||
local RECEIVED_BUBBLE = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble2.png"
|
||||
local RECEIVED_BUBBLE_WITH_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble.png"
|
||||
local RECEIVED_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-tip.png"
|
||||
|
||||
local SENT_BUBBLE = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-self2.png"
|
||||
local SENT_BUBBLE_WITH_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-self.png"
|
||||
local SENT_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-self-tip.png"
|
||||
|
||||
local SENT_BUBBLE_OUTLINE = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble2.png"
|
||||
local SENT_BUBBLE_OUTLINE_WITH_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-right.png"
|
||||
local SENT_OUTLINE_TAIL = "rbxasset://textures/ui/LuaChat/9-slice/chat-bubble-tip-right.png"
|
||||
|
||||
local FFlagLuaChatInfiniteRelayoutRecursionFix = settings():GetFFlag("LuaChatInfiniteRelayoutRecursionFix")
|
||||
|
||||
local function isOutgoingMessage(message)
|
||||
local localUserId = tostring(Players.LocalPlayer.UserId)
|
||||
return message.senderTargetId == localUserId
|
||||
end
|
||||
|
||||
local function isMessageSending(conversation, message)
|
||||
if conversation and conversation.sendingMessages then
|
||||
return conversation.sendingMessages:Get(message.id) ~= nil
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local PROTOCOL_IDENTIFIERS = {
|
||||
"https?://", ""
|
||||
}
|
||||
|
||||
local RESOURCE_NAMES = {
|
||||
"www%.", "web%.", ""
|
||||
}
|
||||
|
||||
local WHITELISTED_DOMAINS = {
|
||||
"roblox", "sitetest%d%.robloxlabs", "gametest%d%.robloxlabs"
|
||||
}
|
||||
|
||||
local MESSAGE_CONTENT_PATTERNS = {
|
||||
GAME_LINK = "%.com/games[^%d]*(%d+)/?",
|
||||
}
|
||||
|
||||
local ChatBubble = {}
|
||||
|
||||
ChatBubble.__index = ChatBubble
|
||||
|
||||
ChatBubble.BubbleType = {
|
||||
AssetCard = "AssetCard",
|
||||
ChatBubble = "UserChatBubble",
|
||||
}
|
||||
|
||||
local function getBubbleImages(message, bubbleType)
|
||||
if isOutgoingMessage(message) and bubbleType ~= ChatBubble.BubbleType.AssetCard then
|
||||
return SENT_BUBBLE, SENT_BUBBLE_WITH_TAIL, SENT_TAIL
|
||||
elseif isOutgoingMessage(message) then
|
||||
return SENT_BUBBLE_OUTLINE, SENT_BUBBLE_OUTLINE_WITH_TAIL, SENT_OUTLINE_TAIL
|
||||
else
|
||||
return RECEIVED_BUBBLE, RECEIVED_BUBBLE_WITH_TAIL, RECEIVED_TAIL
|
||||
end
|
||||
end
|
||||
|
||||
function ChatBubble.new(appState, message, width)
|
||||
width = width or 0
|
||||
|
||||
local self = {}
|
||||
setmetatable(self, ChatBubble)
|
||||
|
||||
local conversationId = message.conversationId
|
||||
local isSending = isMessageSending(appState.store:getState().ChatAppReducer.Conversations[conversationId], message)
|
||||
|
||||
if FFlagLuaChatInfiniteRelayoutRecursionFix then
|
||||
self.width = width
|
||||
end
|
||||
self.appState = appState
|
||||
self.message = message
|
||||
self.bubbles = {}
|
||||
self.connections = {}
|
||||
if FFlagLuaChatToSplitRbxConnections then
|
||||
self.rbx_connections = {}
|
||||
end
|
||||
self.tailVisible = false
|
||||
|
||||
self.rbx = Create.new "Frame" {
|
||||
Name = "ChatContainer",
|
||||
BackgroundTransparency = 1,
|
||||
|
||||
Size = UDim2.new(1, 0, 0, 0),
|
||||
|
||||
Create.new "UIListLayout" {
|
||||
SortOrder = Enum.SortOrder.LayoutOrder,
|
||||
},
|
||||
}
|
||||
|
||||
if message.moderated or isSending then
|
||||
self:AddBubble(UserChatBubble.new(appState, message, nil, self.width), 1)
|
||||
|
||||
-- Specifically whitelist strings with .com/games in the url
|
||||
elseif message.content:lower():match(MESSAGE_CONTENT_PATTERNS.GAME_LINK) then
|
||||
local text = self:FilterForLinks()
|
||||
|
||||
-- Flush remaining text if it is not empty
|
||||
if text:gsub("%s+","") ~= "" then
|
||||
self:AddBubble(UserChatBubble.new(appState, message, text, self.width))
|
||||
end
|
||||
else
|
||||
self:AddBubble(UserChatBubble.new(appState, message, nil, self.width), 1)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function ChatBubble:FilterForLinks()
|
||||
local text = self.message.content
|
||||
for _, protocol in pairs(PROTOCOL_IDENTIFIERS) do
|
||||
for _, resource in pairs(RESOURCE_NAMES) do
|
||||
for _, domain in pairs(WHITELISTED_DOMAINS) do
|
||||
|
||||
local constructedUrlPattern = protocol .. resource .. domain .. MESSAGE_CONTENT_PATTERNS.GAME_LINK
|
||||
for assetId in text:lower():gmatch(constructedUrlPattern) do
|
||||
local linkStart, endLink = text:lower():find("[^%s*]*" .. constructedUrlPattern .. "[^%s*]*")
|
||||
if linkStart then
|
||||
local textBefore = text:sub(1, linkStart - 1)
|
||||
|
||||
if textBefore:gsub("%s+","") ~= "" then
|
||||
self:AddBubble(UserChatBubble.new(self.appState, self.message, textBefore, self.width))
|
||||
end
|
||||
|
||||
self:AddBubble(AssetCard.new(self.appState, self.message, assetId))
|
||||
|
||||
text = text:sub(endLink + 1)
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function ChatBubble:AddBubble(bubble, placement)
|
||||
table.insert(self.bubbles, placement or #self.bubbles+1 ,bubble)
|
||||
bubble.rbx.Parent = self.rbx
|
||||
bubble.LayoutOrder = placement or #self.bubbles
|
||||
|
||||
for i=1,#self.bubbles do
|
||||
self.bubbles[i].LayoutOrder = i
|
||||
end
|
||||
|
||||
local connection = bubble.rbx:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
|
||||
self:Resize()
|
||||
end)
|
||||
if FFlagLuaChatToSplitRbxConnections then
|
||||
table.insert(self.rbx_connections, connection)
|
||||
else
|
||||
table.insert(self.connections, connection)
|
||||
end
|
||||
|
||||
self:Update()
|
||||
end
|
||||
|
||||
function ChatBubble:SetUsernameVisible(value)
|
||||
local bubblePos = self.bubbles[1].bubble.Position
|
||||
|
||||
if value then
|
||||
self.bubbles[1].usernameLabel.Visible = true
|
||||
|
||||
self.bubbles[1].bubble.Position = UDim2.new(
|
||||
bubblePos.X.Scale,
|
||||
bubblePos.X.Offset,
|
||||
0,
|
||||
16
|
||||
)
|
||||
else
|
||||
self.bubbles[1].usernameLabel.Visible = false
|
||||
|
||||
self.bubbles[1].bubble.Position = UDim2.new(
|
||||
bubblePos.X.Scale,
|
||||
bubblePos.X.Offset,
|
||||
0,
|
||||
0
|
||||
)
|
||||
end
|
||||
|
||||
self:Resize()
|
||||
end
|
||||
|
||||
function ChatBubble:SetTypingIndicatorVisible(value)
|
||||
if value and not self.indicator then
|
||||
local indicator = TypingIndicator.new(self.appState, .4)
|
||||
indicator.rbx.AnchorPoint = Vector2.new(0,0.5)
|
||||
indicator.rbx.Position = UDim2.new(0, self.bubbles[1].usernameLabel.TextBounds.X + 3, 0.5, 0)
|
||||
indicator.rbx.Parent = self.bubbles[1].usernameLabel
|
||||
|
||||
self.indicator = indicator
|
||||
elseif self.indicator and not value then
|
||||
self.indicator:Destroy()
|
||||
self.indicator = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ChatBubble:SetThumbnailVisible(value)
|
||||
if value then
|
||||
self.thumbnail = UserThumbnail.new(self.appState, self.message.senderTargetId, true)
|
||||
self.thumbnail.rbx.Position = UDim2.new(0, 10, 0, 0)
|
||||
self.thumbnail.rbx.Overlay.ImageColor3 = Constants.Color.GRAY6
|
||||
self.thumbnail.rbx.Parent = self.bubbles[1].bubbleContainer
|
||||
|
||||
self.thumbnail.clicked:connect(function()
|
||||
local user = self.appState.store:getState().Users[self.message.senderTargetId]
|
||||
local userId = user and user.id
|
||||
if userId then
|
||||
GuiService:BroadcastNotification(WebApi.MakeUserProfileUrl(userId),
|
||||
NotificationType.VIEW_PROFILE)
|
||||
end
|
||||
end)
|
||||
else
|
||||
if self.thumbnail then
|
||||
self.thumbnail:Destruct()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ChatBubble:SetTailVisible(value)
|
||||
self.tailVisible = value
|
||||
if not self.bubbles[1] then return end
|
||||
|
||||
for i, bubble in pairs(self.bubbles) do
|
||||
local bubbleImage, bubbleWithTail, tailImage = getBubbleImages(self.message, bubble.bubbleType)
|
||||
if value and i == 1 then
|
||||
bubble.bubble.Image = bubbleWithTail
|
||||
bubble.tail.Image = tailImage
|
||||
bubble.tail.Visible = true
|
||||
else
|
||||
bubble.bubble.Image = bubbleImage
|
||||
bubble.tail.Visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ChatBubble:SetPaddingObject(object)
|
||||
if not self.bubbles[1] then return end
|
||||
|
||||
if self.bubbles[1].paddingObject then
|
||||
self.bubbles[1].paddingObject:Destroy()
|
||||
end
|
||||
|
||||
object.LayoutOrder = 1
|
||||
object.Parent = self.bubbles[1].rbx
|
||||
self.bubbles[1].paddingObject = object
|
||||
self.bubbles[1]:Resize()
|
||||
end
|
||||
|
||||
function ChatBubble:Resize()
|
||||
if not FFlagLuaChatInfiniteRelayoutRecursionFix then
|
||||
for _,bubble in pairs(self.bubbles) do
|
||||
bubble:Resize()
|
||||
end
|
||||
end
|
||||
|
||||
local height = 0
|
||||
for _, child in ipairs(self.rbx:GetChildren()) do
|
||||
if child:IsA("GuiObject") then
|
||||
height = height + child.AbsoluteSize.Y
|
||||
end
|
||||
end
|
||||
|
||||
self.rbx.Size = UDim2.new(1, 0, 0, height)
|
||||
end
|
||||
|
||||
|
||||
function ChatBubble:Update()
|
||||
self:SetTailVisible(self.tailVisible)
|
||||
self:Resize()
|
||||
end
|
||||
|
||||
function ChatBubble:Destruct()
|
||||
for _, connection in ipairs(self.connections) do
|
||||
connection:disconnect()
|
||||
end
|
||||
self.connections = {}
|
||||
if FFlagLuaChatToSplitRbxConnections then
|
||||
for _, connection in ipairs(self.rbx_connections) do
|
||||
connection:Disconnect()
|
||||
end
|
||||
self.rbx_connections = {}
|
||||
end
|
||||
|
||||
for _, bubble in ipairs(self.bubbles) do
|
||||
bubble:Destruct()
|
||||
end
|
||||
|
||||
if self.thumbnail then
|
||||
self.thumbnail:Destruct()
|
||||
end
|
||||
self.thumbnail = nil
|
||||
|
||||
self.rbx:Destroy()
|
||||
end
|
||||
|
||||
return ChatBubble
|
||||
Reference in New Issue
Block a user