673 lines
20 KiB
Lua
673 lines
20 KiB
Lua
--
|
|
-- ChatGameDrawer
|
|
--
|
|
-- Contains ChatGameCard objects that represent pinned or in progress games.
|
|
-- This lives at the top of a conversation window.
|
|
--
|
|
|
|
local CoreGui = game:GetService("CoreGui")
|
|
local GuiService = game:GetService("GuiService")
|
|
local HttpService = game:GetService("HttpService")
|
|
local PlayerService = game:GetService("Players")
|
|
|
|
local Modules = CoreGui.RobloxGui.Modules
|
|
|
|
local Common = Modules.Common
|
|
local LuaApp = Modules.LuaApp
|
|
local LuaChat = Modules.LuaChat
|
|
|
|
local Analytics = require(Common.Analytics)
|
|
local ChatGameCard = require(LuaChat.Components.ChatGameCard)
|
|
local Constants = require(LuaApp.Constants)
|
|
local GameParams = require(LuaChat.Models.GameParams)
|
|
local FlagSettings = require(LuaChat.FlagSettings)
|
|
local PlayTogetherActions = require(LuaChat.Actions.PlayTogetherActions)
|
|
local Roact = require(Common.Roact)
|
|
local RoactRodux = require(Common.RoactRodux)
|
|
local SortedActivelyPlayedGames = require(LuaChat.SortedActivelyPlayedGames)
|
|
local User = require(LuaApp.Models.User)
|
|
|
|
local ChatGameDrawer = Roact.PureComponent:extend("ChatGameDrawer")
|
|
|
|
local urlSupportNewGamesAPI = settings():GetFFlag("UrlSupportNewGamesAPI")
|
|
|
|
local luaChatPlayTogetherJoinGameInstance = FlagSettings.LuaChatPlayTogetherJoinGameInstance()
|
|
|
|
-- Drawer properties:
|
|
local DRAWER_BACKGROUND_COLOR = Constants.Color.WHITE
|
|
local BORDER_SIZE = 12
|
|
local DRAWER_SHADOW_IMAGE = "rbxasset://textures/ui/LuaChat/graphic/gr-overlay-shadow.png"
|
|
local DRAWER_SHADOW_HEIGHT = 5
|
|
|
|
-- Pointer up to the image:
|
|
local ICON_POINTER_HEIGHT = 6
|
|
local ICON_POINTER_WIDTH = 12
|
|
local ICON_POINTER_UP = "rbxasset://textures/ui/LuaApp/dropdown/gr-tip-up.png"
|
|
local ICON_POINTER_FROMEDGE = 20
|
|
|
|
-- "Pinned Game" text properties:
|
|
local PINNED_ICON = "rbxasset://textures/ui/LuaChat/icons/ic-pin.png"
|
|
local PINNED_ICON_SIZE = 12
|
|
local PINNED_SPACER = 6
|
|
|
|
local PINNED_TEXT_COLOR = Constants.Color.GRAY2
|
|
local PINNED_TEXT_FONT = Enum.Font.SourceSans
|
|
local PINNED_TEXT_SIZE = 15
|
|
|
|
local PINNED_DIVIDER_COLOR = Constants.Color.GRAY4
|
|
local PINNED_BOTTOM_BORDER = Constants.Color.GRAY4
|
|
local PINNED_BOTTOM_BACKGROUND = Constants.Color.GRAY6
|
|
|
|
local SMALL_DIVIDER_OFFSET = 60
|
|
local CARD_HEIGHT_SMALL = 60
|
|
local CARD_HEIGHT_LARGE = 84
|
|
|
|
local MORE_TEXT_SIZE = 18
|
|
local MORE_TEXT_PADDING = 9
|
|
local MORE_TEXT_COLOR = Constants.Color.GRAY1
|
|
|
|
-- Set up some default state for this control:
|
|
function ChatGameDrawer:init()
|
|
self._analytics = Analytics.new()
|
|
self.state = {
|
|
isExpanded = false,
|
|
pointerPosition = UDim2.new(1, -ICON_POINTER_FROMEDGE, 0, 0),
|
|
pointerSet = false,
|
|
renderWidth = 0,
|
|
}
|
|
|
|
self.isGameDrawerSized = false
|
|
end
|
|
|
|
function ChatGameDrawer:UnpinGame()
|
|
local playTogetherUnpinGame = self.props.playTogetherUnpinGame
|
|
playTogetherUnpinGame(self.props.conversationId)
|
|
end
|
|
|
|
-- Games are pinned by universeId (but they're accessed using placeId elsewhere):
|
|
function ChatGameDrawer:PinGame(universeId)
|
|
local playTogetherPinGame = self.props.playTogetherPinGame
|
|
playTogetherPinGame(self.props.conversationId, universeId)
|
|
end
|
|
|
|
function ChatGameDrawer:ViewGameDetails(placeId)
|
|
GuiService:BroadcastNotification(placeId, GuiService:GetNotificationTypeList().VIEW_GAME_DETAILS_ANIMATED)
|
|
end
|
|
|
|
function ChatGameDrawer:GameStart(game)
|
|
local placeId = game.placeId
|
|
|
|
if luaChatPlayTogetherJoinGameInstance then
|
|
local friends = game.friends
|
|
if #friends == 0 then
|
|
-- No friends are here, join naively:
|
|
self:GamePlayPlace(placeId)
|
|
else
|
|
-- We have friends! Go join them:
|
|
local friend = friends[1]
|
|
if friend.placeId == friend.rootPlaceId then
|
|
-- If our friend is in the root instance, we can join the same instance:
|
|
self:GameJoinInstance(friend.placeId, friend.rootPlaceId, friend.gameInstanceId)
|
|
else
|
|
-- Otherwise, we must join to their playerID:
|
|
self:GameJoinUser(friend.uid, friend.placeId, friend.rootPlaceId)
|
|
end
|
|
end
|
|
else
|
|
self:GamePlayPlace(placeId)
|
|
end
|
|
end
|
|
|
|
function ChatGameDrawer:GamePlayPlace(placeId)
|
|
-- Report player start game via play together:
|
|
self:ReportGamePlayIntent(placeId)
|
|
self:ReportPlayerPlayGame(placeId)
|
|
|
|
-- Start a game:
|
|
local gameParams = GameParams.fromPlaceId(placeId)
|
|
local payload = HttpService:JSONEncode(gameParams)
|
|
GuiService:BroadcastNotification(payload, GuiService:GetNotificationTypeList().LAUNCH_GAME)
|
|
end
|
|
|
|
function ChatGameDrawer:GameJoinUser(userId, placeId, rootPlaceId)
|
|
-- Report player join game via play together:
|
|
self:ReportGamePlayIntent(rootPlaceId)
|
|
self:ReportPlayerJoinGame(placeId, rootPlaceId, nil)
|
|
|
|
-- Join a game:
|
|
local gameParams = GameParams.fromUserId(userId)
|
|
local payload = HttpService:JSONEncode(gameParams)
|
|
GuiService:BroadcastNotification(payload, GuiService:GetNotificationTypeList().LAUNCH_GAME)
|
|
end
|
|
|
|
function ChatGameDrawer:GameJoinInstance(placeId, rootPlaceId, gameInstanceId)
|
|
-- Report player join game via play together:
|
|
self:ReportGamePlayIntent(rootPlaceId)
|
|
self:ReportPlayerJoinGame(placeId, rootPlaceId, gameInstanceId)
|
|
|
|
-- Join a game:
|
|
local gameParams = GameParams.fromPlaceInstance(placeId, gameInstanceId)
|
|
local payload = HttpService:JSONEncode(gameParams)
|
|
GuiService:BroadcastNotification(payload, GuiService:GetNotificationTypeList().LAUNCH_GAME)
|
|
end
|
|
|
|
function ChatGameDrawer:GetGamesFromConversation(conversationId)
|
|
local conversations = self.props.conversations
|
|
local mostRecentlyPlayedGames = self.props.mostRecentlyPlayedGames
|
|
local users = self.props.users
|
|
|
|
-- Don't know if this is necessary:
|
|
if not urlSupportNewGamesAPI then
|
|
error("Server doesn't support new games API.")
|
|
return { countFriendsInGames = 0, games = {}, }
|
|
end
|
|
|
|
-- Early out if we have no conversation:
|
|
if conversationId == nil or conversationId == "nil" then
|
|
return { countFriendsInGames = 0, games = {}, }
|
|
end
|
|
|
|
-- Find the specific conversation we're interested in:
|
|
if not conversations then
|
|
return { countFriendsInGames = 0, games = {}, }
|
|
end
|
|
|
|
local conversation = conversations[conversationId]
|
|
if not conversation then
|
|
warn("ChatGameDrawer - Can't find conversation, id:" .. conversationId .. " t:" .. type(conversationId))
|
|
return { countFriendsInGames = 0, games = {}, }
|
|
end
|
|
|
|
local pinnedGameRootPlaceId = conversation.pinnedGame.rootPlaceId
|
|
local inGameParticipants = {}
|
|
local mostRecentPlayedPlayableGamePlaceId = mostRecentlyPlayedGames.playableGamePlaceId
|
|
local localPlayerId = tostring(PlayerService.LocalPlayer.UserId)
|
|
|
|
for _, userId in pairs(conversation.participants) do
|
|
if userId ~= localPlayerId then
|
|
local user = users[userId]
|
|
if user ~= nil then
|
|
if (user.presence == User.PresenceType.IN_GAME) and user.placeId then
|
|
table.insert(inGameParticipants, user)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local countFriendsInGames = #inGameParticipants
|
|
if countFriendsInGames > 0 then
|
|
return {
|
|
countFriendsInGames = countFriendsInGames,
|
|
games = SortedActivelyPlayedGames.getSortedGamesPlusEmptyPinned(pinnedGameRootPlaceId, inGameParticipants),
|
|
}
|
|
end
|
|
|
|
if pinnedGameRootPlaceId then
|
|
return {
|
|
countFriendsInGames = 0,
|
|
games = {
|
|
{
|
|
friends = {},
|
|
pinned = true,
|
|
placeId = pinnedGameRootPlaceId,
|
|
recommended = false,
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
if mostRecentPlayedPlayableGamePlaceId then
|
|
return {
|
|
countFriendsInGames = 0,
|
|
games = {
|
|
{
|
|
friends = {},
|
|
pinned = false,
|
|
placeId = mostRecentPlayedPlayableGamePlaceId,
|
|
recommended = true,
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
return {
|
|
countFriendsInGames = 0,
|
|
games = {}
|
|
}
|
|
end
|
|
|
|
function ChatGameDrawer:ReportGamePlayIntent(rootPlaceId)
|
|
local conversationId = self.props.conversationId
|
|
local eventContext = "PlayGameFromPlayTogether"
|
|
local eventName = "gamePlayIntent"
|
|
|
|
local player = PlayerService.LocalPlayer
|
|
local userId = "UNKNOWN"
|
|
if player then
|
|
userId = tostring(player.UserId)
|
|
end
|
|
|
|
local additionalArgs = {
|
|
uid = userId,
|
|
rootPlaceId = rootPlaceId,
|
|
}
|
|
self._analytics.EventStream:setRBXEventStream(eventContext, eventName, additionalArgs)
|
|
end
|
|
|
|
function ChatGameDrawer:ReportPlayerPlayGame(placeId)
|
|
local conversationId = self.props.conversationId
|
|
local eventContext = "touch"
|
|
local eventName = "clickPlayButtonInPlayTogether"
|
|
|
|
local player = PlayerService.LocalPlayer
|
|
local userId = "UNKNOWN"
|
|
if player then
|
|
userId = tostring(player.UserId)
|
|
end
|
|
|
|
local additionalArgs = {
|
|
uid = userId,
|
|
cid = conversationId,
|
|
placeId = placeId
|
|
}
|
|
self._analytics.EventStream:setRBXEventStream(eventContext, eventName, additionalArgs)
|
|
end
|
|
|
|
function ChatGameDrawer:ReportPlayerJoinGame(placeId, rootPlaceId, gameInstanceId)
|
|
local conversationId = self.props.conversationId
|
|
local eventContext = "touch"
|
|
local eventName = "clickJoinButtonInPlayTogether"
|
|
|
|
local player = PlayerService.LocalPlayer
|
|
local userId = "UNKNOWN"
|
|
if player then
|
|
userId = tostring(player.UserId)
|
|
end
|
|
|
|
local additionalArgs = {
|
|
uid = userId,
|
|
conversationId = conversationId,
|
|
placeId = placeId,
|
|
rootPlaceId = rootPlaceId,
|
|
gameInstanceId = gameInstanceId,
|
|
}
|
|
self._analytics.EventStream:setRBXEventStream(eventContext, eventName, additionalArgs)
|
|
end
|
|
|
|
function ChatGameDrawer:render()
|
|
local anchorPoint = self.props.AnchorPoint
|
|
local conversationId = self.props.conversationId
|
|
local isGameDrawerOpen = self.props.isGameDrawerOpen
|
|
local localization = self.props.Localization
|
|
local onSize = self.props.onSize
|
|
local parentLayoutOrder = self.props.layoutOrder
|
|
local position = self.props.Position
|
|
|
|
local isExpanded = self.state.isExpanded
|
|
local pointerPosition = self.state.pointerPosition or UDim2.new(1, -ICON_POINTER_FROMEDGE, 0, 0)
|
|
local pointerSet = self.state.pointerSet
|
|
local pointerTransparency = 1
|
|
if pointerSet then
|
|
pointerTransparency = 0
|
|
end
|
|
|
|
local gameInfo = self:GetGamesFromConversation(conversationId)
|
|
local countGames = #gameInfo.games
|
|
|
|
-- Early exit if we have nothing to display in the drawer:
|
|
if countGames == 0 then
|
|
spawn(function()
|
|
onSize(0, false)
|
|
end)
|
|
return nil
|
|
end
|
|
|
|
local hasFriendsActive = gameInfo.countFriendsInGames > 0
|
|
|
|
-- If we have active friends and this is the first time rendering, expand:
|
|
if hasFriendsActive and not self.isGameDrawerSized then
|
|
self.isGameDrawerSized = true
|
|
if not isExpanded then
|
|
spawn(function()
|
|
self:setState({ isExpanded = true })
|
|
end)
|
|
return nil
|
|
end
|
|
end
|
|
|
|
-- Build up our drop-down items here for display inside our main element:
|
|
local gameItems = {}
|
|
local drawerHeight = 0
|
|
gameItems["Layout"] = Roact.createElement("UIListLayout", {
|
|
FillDirection = Enum.FillDirection.Vertical,
|
|
HorizontalAlignment = Enum.HorizontalAlignment.Center,
|
|
SortOrder = Enum.SortOrder.LayoutOrder,
|
|
VerticalAlignment = Enum.VerticalAlignment.Top,
|
|
})
|
|
|
|
-- Display our pinned game (if we have one):
|
|
local layoutOrder = 1
|
|
local hasPinnedGame = false
|
|
|
|
for _, game in ipairs(gameInfo.games) do
|
|
if game.pinned then
|
|
hasPinnedGame = true
|
|
local placeId = game.placeId
|
|
|
|
gameItems["PinnedTitle"] = Roact.createElement("TextButton", {
|
|
AutoButtonColor = false,
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, 0, 0, PINNED_ICON_SIZE + (BORDER_SIZE * 2)),
|
|
Text = "",
|
|
}, {
|
|
Icon = Roact.createElement("ImageLabel", {
|
|
AnchorPoint = Vector2.new(0, 0.5),
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
Image = PINNED_ICON,
|
|
Position = UDim2.new(0, BORDER_SIZE, 0.5, 0),
|
|
Size = UDim2.new(0, PINNED_ICON_SIZE, 0, PINNED_ICON_SIZE),
|
|
}),
|
|
|
|
Text = Roact.createElement("TextLabel", {
|
|
AnchorPoint = Vector2.new(0, 0.5),
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
Font = PINNED_TEXT_FONT,
|
|
Position = UDim2.new(0, BORDER_SIZE + PINNED_ICON_SIZE + PINNED_SPACER, 0.5, 0),
|
|
Size = UDim2.new(1, -(PINNED_ICON_SIZE + PINNED_SPACER + (BORDER_SIZE * 2)), 1, 0),
|
|
Text = localization:Format("Feature.Chat.Drawer.PinnedGame"),
|
|
TextColor3 = PINNED_TEXT_COLOR,
|
|
TextSize = PINNED_TEXT_SIZE,
|
|
TextXAlignment = Enum.TextXAlignment.Left,
|
|
TextYAlignment = Enum.TextYAlignment.Center,
|
|
}),
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + PINNED_ICON_SIZE + (BORDER_SIZE * 2)
|
|
|
|
gameItems["Divider"] = Roact.createElement("Frame", {
|
|
BackgroundColor3 = PINNED_DIVIDER_COLOR,
|
|
BorderSizePixel = 0,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, -(BORDER_SIZE * 2), 0, 1),
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + 1
|
|
|
|
-- Index by pinned status and placeId:
|
|
gameItems["Pinned" .. placeId] = Roact.createElement(ChatGameCard, {
|
|
game = game,
|
|
conversationId = conversationId,
|
|
isGameDrawerOpen = isGameDrawerOpen,
|
|
isPinnedGame = true,
|
|
LayoutOrder = layoutOrder,
|
|
Localization = localization,
|
|
renderWidth = self.state.renderWidth,
|
|
onGameStart = function()
|
|
self:GameStart(game)
|
|
end,
|
|
onGameUnpin = function()
|
|
self:UnpinGame()
|
|
end,
|
|
onViewDetails = function()
|
|
self:ViewGameDetails(placeId)
|
|
end,
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + CARD_HEIGHT_LARGE
|
|
|
|
-- If we have more games to display, add a spacer between the pinned and regular games:
|
|
if (countGames > 1) then
|
|
gameItems["Spacer"] = Roact.createElement("Frame", {
|
|
BackgroundColor3 = PINNED_BOTTOM_BACKGROUND,
|
|
BackgroundTransparency = 0,
|
|
BorderColor3 = PINNED_BOTTOM_BORDER,
|
|
BorderSizePixel = 1,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, 0, 0, PINNED_SPACER),
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + PINNED_SPACER
|
|
end
|
|
|
|
-- Done, we found our pinned game in the list:
|
|
break
|
|
end
|
|
end
|
|
|
|
-- Display all the other games in progress - but only if we don't have a
|
|
-- pinned game or we're expanded:
|
|
if (not hasPinnedGame) or isExpanded then
|
|
local hasRegularGame = false
|
|
for _, game in ipairs(gameInfo.games) do
|
|
if not game.pinned then
|
|
-- If we've already added a regular game, insert a spacer before the next:
|
|
if hasRegularGame then
|
|
gameItems[layoutOrder] = Roact.createElement("Frame", {
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, 0, 0, 1),
|
|
},{
|
|
divider = Roact.createElement("Frame", {
|
|
AnchorPoint = Vector2.new(1, 0),
|
|
BorderSizePixel = 0,
|
|
BackgroundColor3 = PINNED_DIVIDER_COLOR,
|
|
Position = UDim2.new(1, 0, 0, 0),
|
|
Size = UDim2.new(1, -SMALL_DIVIDER_OFFSET, 0, 1),
|
|
}),
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + 1
|
|
end
|
|
|
|
local placeId = game.placeId
|
|
-- Index as an unpinned game and placeId:
|
|
gameItems["Game" .. placeId] = Roact.createElement(ChatGameCard, {
|
|
game = game,
|
|
conversationId = conversationId,
|
|
isGameDrawerOpen = isGameDrawerOpen,
|
|
isPinnedGame = false,
|
|
isRecommended = game.recommended,
|
|
LayoutOrder = layoutOrder,
|
|
Localization = localization,
|
|
renderWidth = self.state.renderWidth,
|
|
onGameStart = function()
|
|
self:GameStart(game)
|
|
end,
|
|
onGamePin = function(universeId)
|
|
self:PinGame(universeId)
|
|
end,
|
|
onViewDetails = function()
|
|
self:ViewGameDetails(placeId)
|
|
end,
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + CARD_HEIGHT_SMALL
|
|
|
|
-- If we're not expanded, we've hit our limit:
|
|
if not isExpanded then
|
|
break
|
|
end
|
|
|
|
-- Next card will have a spacer before it.
|
|
hasRegularGame = true
|
|
end
|
|
end
|
|
end
|
|
|
|
-- The final item in the list should be the text to either show more or hide:
|
|
local endTextDivider = false
|
|
local endTextShow = false
|
|
local endLocalizeText = ""
|
|
if countGames == 0 then
|
|
endTextShow = true
|
|
endLocalizeText = localization:Format("Feature.Chat.Drawer.NoGames")
|
|
elseif countGames > 1 then
|
|
if isExpanded then
|
|
endLocalizeText = localization:Format("Feature.Chat.Drawer.ShowLess")
|
|
else
|
|
endLocalizeText = localization:Format("Feature.Chat.Drawer.ShowMore") .. " (+" .. (countGames - 1) .. ")"
|
|
end
|
|
endTextDivider = true
|
|
endTextShow = true
|
|
end
|
|
|
|
if endTextShow then
|
|
if endTextDivider then
|
|
gameItems["DividerBottom"] = Roact.createElement("Frame", {
|
|
BorderSizePixel = 0,
|
|
BackgroundColor3 = PINNED_DIVIDER_COLOR,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, 0, 0, 1),
|
|
})
|
|
layoutOrder = layoutOrder + 1
|
|
drawerHeight = drawerHeight + PINNED_SPACER
|
|
end
|
|
|
|
gameItems["ShowButton"] = Roact.createElement("TextButton", {
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
Font = PINNED_TEXT_FONT,
|
|
LayoutOrder = layoutOrder,
|
|
Size = UDim2.new(1, 0, 0, MORE_TEXT_SIZE + (MORE_TEXT_PADDING * 2)),
|
|
Text = endLocalizeText,
|
|
TextColor3 = MORE_TEXT_COLOR,
|
|
TextSize = MORE_TEXT_SIZE,
|
|
[Roact.Event.Activated] = function()
|
|
self:setState({ isExpanded = not self.state.isExpanded })
|
|
end
|
|
})
|
|
drawerHeight = drawerHeight + MORE_TEXT_SIZE + (MORE_TEXT_PADDING * 2)
|
|
end
|
|
|
|
-- Define the shadow component to hang off the bottom of the list:
|
|
-- Note: Do not count the height since this isn't inside the frame.
|
|
local shadow = Roact.createElement("ImageLabel", {
|
|
BackgroundTransparency = 1,
|
|
Image = DRAWER_SHADOW_IMAGE,
|
|
Size = UDim2.new(1, 0, 0, DRAWER_SHADOW_HEIGHT),
|
|
Position = UDim2.new(0, 0, 1, 0),
|
|
})
|
|
|
|
spawn(function()
|
|
onSize(drawerHeight, hasFriendsActive)
|
|
end)
|
|
|
|
-- Create and return the main control itself:
|
|
return Roact.createElement("Frame", {
|
|
AnchorPoint = anchorPoint,
|
|
BackgroundColor3 = DRAWER_BACKGROUND_COLOR,
|
|
BackgroundTransparency = 0,
|
|
BorderSizePixel = 0,
|
|
ClipsDescendants = false,
|
|
LayoutOrder = parentLayoutOrder,
|
|
Position = position,
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
[Roact.Ref] = function(rbx)
|
|
if not rbx then
|
|
return
|
|
end
|
|
spawn(function()
|
|
self:resolveMetrics(rbx)
|
|
end)
|
|
end,
|
|
}, {
|
|
Pointer = Roact.createElement("ImageLabel", {
|
|
AnchorPoint = Vector2.new(0.5, 1),
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
Image = ICON_POINTER_UP,
|
|
ImageTransparency = pointerTransparency,
|
|
Position = pointerPosition,
|
|
Size = UDim2.new(0, ICON_POINTER_WIDTH, 0, ICON_POINTER_HEIGHT),
|
|
}),
|
|
Shadow = shadow,
|
|
|
|
Frame = Roact.createElement("Frame", {
|
|
BackgroundTransparency = 1,
|
|
BorderSizePixel = 0,
|
|
ClipsDescendants = true,
|
|
Size = UDim2.new(1, 0, 1, 0),
|
|
},
|
|
gameItems
|
|
)
|
|
})
|
|
end
|
|
|
|
function ChatGameDrawer:resolveMetrics(rbx)
|
|
-- This function finds the ActiveGameIcon and positions an arrow pointing
|
|
-- at it from our open drawer. The position of the icon can change depending
|
|
-- on a number of factors so it can't be hardcoded.
|
|
--
|
|
-- Also retrieves the actual width of our drawer to pass to child components
|
|
-- which need to be width-aware to render properly.
|
|
--
|
|
-- Note 1: I didn't want to attach this on the icon because it needs to line
|
|
-- up with the edge of the drawer.)
|
|
--
|
|
-- Note 2: we can't examine the GameDrawer position here because on the
|
|
-- initial pass through it is invisible with a position of 0,0 on screen.
|
|
|
|
-- Find the conversation header:
|
|
local header = rbx:FindFirstAncestor("HeaderFrame")
|
|
if header == nil then
|
|
warn("Couldn't find header.")
|
|
return
|
|
end
|
|
|
|
-- Find the "Play Together" icon:
|
|
local iconPlayTogether = header:FindFirstChild("TopGameIcon", true)
|
|
if iconPlayTogether == nil then
|
|
warn("Couldn't find Play Together icon.")
|
|
return
|
|
end
|
|
|
|
-- Figure out where on the screen iconPlayTogether is, so
|
|
-- we can position our pointer directly underneath it:
|
|
local iconFromEdge = (header.AbsolutePosition.X + header.AbsoluteSize.X) -
|
|
(iconPlayTogether.AbsolutePosition.X + (iconPlayTogether.AbsoluteSize.X * 0.5))
|
|
|
|
-- Track our drawer's width for content-aware scaling:
|
|
local renderWidth = rbx.AbsoluteSize.X
|
|
|
|
-- Prevent updating metrics if we already have the correct values:
|
|
if (not self.state.pointerSet) or
|
|
(self.state.renderWidth ~= renderWidth) or
|
|
(self.state.pointerPosition.X.Offset ~= -iconFromEdge) then
|
|
-- Update the pointer position state so it will render in the correct location:
|
|
-- Yes, we're using another spawn call here - but we need the 1-frame delay.
|
|
spawn(function()
|
|
self:setState({
|
|
pointerPosition = UDim2.new(1, -iconFromEdge, 0, 0),
|
|
pointerSet = true,
|
|
renderWidth = renderWidth,
|
|
})
|
|
end)
|
|
end
|
|
end
|
|
|
|
ChatGameDrawer = RoactRodux.UNSTABLE_connect2(
|
|
function(state, props)
|
|
return {
|
|
conversations = state.ChatAppReducer.Conversations,
|
|
mostRecentlyPlayedGames = state.ChatAppReducer.MostRecentlyPlayedGames,
|
|
users = state.Users,
|
|
}
|
|
end,
|
|
function(dispatch)
|
|
return {
|
|
playTogetherUnpinGame = function(conversationId)
|
|
dispatch(PlayTogetherActions.UnpinGame(conversationId))
|
|
end,
|
|
playTogetherPinGame = function(conversationId, universeId)
|
|
dispatch(PlayTogetherActions.PinGame(conversationId, universeId))
|
|
end,
|
|
}
|
|
end
|
|
)(ChatGameDrawer)
|
|
|
|
return ChatGameDrawer |