303 lines
8.6 KiB
Lua
303 lines
8.6 KiB
Lua
local Players = game:GetService("Players")
|
|
local CoreGui = game:GetService("CoreGui")
|
|
|
|
local LuaApp = CoreGui.RobloxGui.Modules.LuaApp
|
|
|
|
local LuaChat = script.Parent.Parent
|
|
|
|
local Create = require(LuaChat.Create)
|
|
local Constants = require(LuaChat.Constants)
|
|
local Text = require(LuaChat.Text)
|
|
local FormFactor = require(LuaApp.Enum.FormFactor)
|
|
|
|
local FFlagEnableChatMessageType = settings():GetFFlag("EnableChatMessageType")
|
|
local Message = FFlagEnableChatMessageType and require(LuaChat.Models.Message)
|
|
|
|
local BUBBLE_PADDING = 10
|
|
local TEXT_BUBBLE_X_PADDING = 54
|
|
local TEXT_BUBBLE_X_TABLET_ADDITIONAL_PADDING = 112
|
|
|
|
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 UserChatBubble = {}
|
|
|
|
UserChatBubble.__index = UserChatBubble
|
|
function UserChatBubble.new(appState, message, newContent, width)
|
|
local self = {}
|
|
setmetatable(self, UserChatBubble)
|
|
|
|
local conversationId = message.conversationId
|
|
local isSending = isMessageSending(appState.store:getState().ChatAppReducer.Conversations[conversationId], message)
|
|
|
|
local state = appState.store:getState()
|
|
local user = state.Users[message.senderTargetId]
|
|
local username = user and user.name or "unknown user"
|
|
|
|
self.appState = appState
|
|
self.paddingObject = nil
|
|
self.message = message
|
|
self.bubbleType = "UserChatBubble"
|
|
self.connections = {}
|
|
if FFlagLuaChatInfiniteRelayoutRecursionFix then
|
|
self.width = width
|
|
end
|
|
|
|
if FFlagEnableChatMessageType then
|
|
if newContent then
|
|
self.displayMessage = newContent
|
|
elseif self.message.messageType == Message.MessageTypes.PlainText then
|
|
self.displayMessage = self.message.content
|
|
else
|
|
self.displayMessage = ""
|
|
end
|
|
else
|
|
self.displayMessage = newContent and newContent or self.message.content
|
|
end
|
|
|
|
self.textContent = Create.new "TextLabel" {
|
|
Name = "TextContent",
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
BackgroundTransparency = 1,
|
|
TextColor3 = Constants.Color.WHITE,
|
|
TextSize = Constants.Font.FONT_SIZE_18,
|
|
Text = "",
|
|
Font = Enum.Font.SourceSans,
|
|
TextWrapped = true,
|
|
TextXAlignment = Enum.TextXAlignment.Left,
|
|
}
|
|
|
|
self.tail = Create.new "ImageLabel" {
|
|
Name = "Tail",
|
|
Size = UDim2.new(0, 6, 0, 6),
|
|
BackgroundTransparency = 1,
|
|
}
|
|
|
|
self.bubble = Create.new "ImageLabel" {
|
|
Name = "Bubble",
|
|
BackgroundTransparency = 1,
|
|
AnchorPoint = Vector2.new(1, 0),
|
|
Position = UDim2.new(0, 0, 0, 0),
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
ScaleType = Enum.ScaleType.Slice,
|
|
SliceCenter = Rect.new(10, 10, 11, 11),
|
|
LayoutOrder = 2,
|
|
|
|
Create.new "Frame" {
|
|
Name = "Content",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, -BUBBLE_PADDING * 2, 1, -BUBBLE_PADDING * 2),
|
|
AnchorPoint = Vector2.new(0.5, 0.5),
|
|
Position = UDim2.new(0.5, 0, 0.5, 0),
|
|
|
|
self.textContent,
|
|
},
|
|
|
|
self.tail,
|
|
}
|
|
|
|
self.usernameLabel = Create.new "TextLabel" {
|
|
Name = "UsernameLabel",
|
|
Font = Enum.Font.SourceSans,
|
|
TextSize = Constants.Font.FONT_SIZE_12,
|
|
Visible = false,
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, -56, 0, 16),
|
|
Position = UDim2.new(0, 56, 0, 0),
|
|
TextColor3 = Constants.Color.GRAY2,
|
|
TextXAlignment = Enum.TextXAlignment.Left,
|
|
TextYAlignment = Enum.TextYAlignment.Top,
|
|
Text = username,
|
|
}
|
|
|
|
self.bubbleContainer = Create.new "Frame" {
|
|
Name = "BubbleContainer",
|
|
BackgroundTransparency = 1,
|
|
LayoutOrder = 2,
|
|
Size = UDim2.new(1, 0, 0, 1),
|
|
|
|
self.bubble,
|
|
self.usernameLabel,
|
|
}
|
|
|
|
self.rbx = Create.new "Frame" {
|
|
Name = "Message",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(0, 0, 0, 0),
|
|
|
|
Create.new "UIListLayout" {
|
|
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
},
|
|
|
|
self.bubbleContainer,
|
|
}
|
|
|
|
-- 'isOutgoing' means "is sent by the local user". This function separates the tail position & color
|
|
if isOutgoingMessage(message) then
|
|
local bubbleColor = isSending and Constants.Color.BLUE_DISABLED or Constants.Color.BLUE_PRIMARY
|
|
local textTransparency = isSending and Constants.Color.ALPHA_SHADOW_PRIMARY or 0
|
|
|
|
self.tail.AnchorPoint = Vector2.new(0, 0)
|
|
self.tail.Position = UDim2.new(1, 0, 0, 0)
|
|
self.tail.ImageColor3 = bubbleColor
|
|
|
|
self.bubble.ImageColor3 = bubbleColor
|
|
self.bubble.AnchorPoint = Vector2.new(1, 0)
|
|
self.bubble.Position = UDim2.new(1, -10, 0, 0)
|
|
|
|
self.textContent.TextColor3 = Constants.Color.WHITE
|
|
self.textContent.TextTransparency = textTransparency
|
|
|
|
self.rbx.UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Right
|
|
else
|
|
self.tail.AnchorPoint = Vector2.new(1, 0)
|
|
self.tail.Position = UDim2.new(0, 0, 0, 0)
|
|
self.tail.ImageColor3 = Color3.new(1, 1, 1)
|
|
|
|
self.bubble.ImageColor3 = Color3.new(1, 1, 1)
|
|
self.bubble.AnchorPoint = Vector2.new(0, 0)
|
|
self.bubble.Position = UDim2.new(0, TEXT_BUBBLE_X_PADDING, 0, 0)
|
|
|
|
self.textContent.TextColor3 = Constants.Color.GRAY1
|
|
|
|
self.rbx.UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Left
|
|
end
|
|
self:Update(message)
|
|
|
|
if not FFlagLuaChatInfiniteRelayoutRecursionFix then
|
|
local connection = self.rbx:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
|
|
self:Resize()
|
|
end)
|
|
table.insert(self.connections, connection)
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
function UserChatBubble:Resize()
|
|
local padding = (TEXT_BUBBLE_X_PADDING + BUBBLE_PADDING) * 2 -- * 2 for both sides
|
|
if self.appState.store:getState().FormFactor == FormFactor.TABLET then
|
|
padding = padding + TEXT_BUBBLE_X_TABLET_ADDITIONAL_PADDING
|
|
end
|
|
|
|
local viewportWidth
|
|
if FFlagLuaChatInfiniteRelayoutRecursionFix then
|
|
viewportWidth = self.width
|
|
else
|
|
viewportWidth = self.rbx.AbsoluteSize.X
|
|
end
|
|
|
|
local textWidth = viewportWidth - padding
|
|
|
|
local textBounds = Text.GetTextBounds(
|
|
self.textContent.Text,
|
|
self.textContent.Font,
|
|
self.textContent.TextSize,
|
|
Vector2.new(textWidth, 10000)
|
|
)
|
|
|
|
local doublePadding = BUBBLE_PADDING * 2
|
|
self.bubble.Size = UDim2.new(0, textBounds.X + doublePadding, 0, textBounds.Y + doublePadding)
|
|
|
|
local containerHeight = self.bubble.AbsoluteSize.Y
|
|
|
|
if self.usernameLabel.Visible then
|
|
containerHeight = containerHeight + self.usernameLabel.AbsoluteSize.Y
|
|
end
|
|
|
|
self.bubbleContainer.Size = UDim2.new(1, 0, 0, containerHeight)
|
|
|
|
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
|
|
|
|
local function CreateFilteringText(appState, filteringTextKey, textColor)
|
|
return Create.new "Frame" {
|
|
Name = "ModeratedNotice",
|
|
BackgroundTransparency = 1,
|
|
Size = UDim2.new(1, 0, 0, 18),
|
|
LayoutOrder = 3,
|
|
|
|
Create.new "TextLabel" {
|
|
Name = "ModeratedNoticeText",
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
Position = UDim2.new(1, -10, 0, 0),
|
|
AnchorPoint = Vector2.new(1, 0),
|
|
BackgroundTransparency = 1,
|
|
TextColor3 = textColor,
|
|
TextSize = Constants.Font.FONT_SIZE_14,
|
|
Text = appState.localization:Format(filteringTextKey),
|
|
Font = Enum.Font.SourceSans,
|
|
TextXAlignment = Enum.TextXAlignment.Right,
|
|
TextYAlignment = Enum.TextYAlignment.Top,
|
|
}
|
|
}
|
|
end
|
|
|
|
function UserChatBubble:Update(message)
|
|
self.message = message
|
|
|
|
if message.moderated then
|
|
self.displayMessage = string.gsub(self.displayMessage, "[^%s]", "#")
|
|
end
|
|
|
|
self.textContent.Text = self.displayMessage
|
|
|
|
local textColor
|
|
local filteringTextKey = nil
|
|
if message.moderated then
|
|
filteringTextKey = "Feature.Chat.Message.MessageContentModerated"
|
|
textColor = Constants.Color.RED_NEGATIVE
|
|
elseif message.filteredForReceivers then
|
|
filteringTextKey = "Feature.Chat.Message.Default"
|
|
textColor = Constants.Color.GRAY3
|
|
end
|
|
|
|
-- Either the message was moderated or it was filtered for some users (minors).
|
|
if filteringTextKey and (not self.moderatedText) then
|
|
self.moderatedText = CreateFilteringText(self.appState, filteringTextKey, textColor)
|
|
self.moderatedText.Parent = self.rbx
|
|
end
|
|
|
|
-- There was an error and the message was not sent.
|
|
if (message.failed or message.moderated) and (not self.alertIcon) then
|
|
self.alertIcon = Create.new "ImageLabel" {
|
|
Name = "FailedIcon",
|
|
Size = UDim2.new(0, 18, 0, 18),
|
|
AnchorPoint = Vector2.new(1, 0.5),
|
|
Position = UDim2.new(0, -10, 0.5, 0),
|
|
ImageColor3 = Constants.Color.RED_PRIMARY,
|
|
BackgroundTransparency = 1,
|
|
Image = "rbxasset://textures/ui/LuaChat/icons/ic-alert.png"
|
|
}
|
|
self.alertIcon.Parent = self.bubble
|
|
end
|
|
|
|
self:Resize()
|
|
end
|
|
|
|
function UserChatBubble:Destruct()
|
|
for _, connection in ipairs(self.connections) do
|
|
connection:Disconnect()
|
|
end
|
|
self.connections = {}
|
|
self.rbx:Destroy()
|
|
end
|
|
|
|
return UserChatBubble |