Files
watrbx-game-engine/content/scripts/Modules/SortCarousel.lua
T
2025-09-18 17:55:52 -04:00

203 lines
5.7 KiB
Lua

--[[
// SortCarousel.lua
// Creates a sort carousel with data for the sort
]]
local CoreGui = Game:GetService("CoreGui")
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local EventHub = require(Modules:FindFirstChild('EventHub'))
local GameDataModule = require(Modules:FindFirstChild('GameData'))
local ImageSlider = require(Modules:FindFirstChild('ImageSlider'))
local Utility = require(Modules:FindFirstChild('Utility'))
local ThumbnailLoader = require(Modules:FindFirstChild('ThumbnailLoader'))
local GlobalSettings = require(Modules:FindFirstChild('GlobalSettings'))
local LoadingWidget = require(Modules:FindFirstChild('LoadingWidget'))
local SoundManager = require(Modules:FindFirstChild('SoundManager'))
local AssetManager = require(Modules:FindFirstChild('AssetManager'))
local createSortCarousel = function(size, position, gameCollection, parent)
local this = {}
--[[ Constants ]]--
local LOAD_COUNT = 20
local IMAGE_COUNT = 9
local carousel = ImageSlider(size, position)
carousel:SetPadding(18)
carousel:SetParent(parent)
--[[ Variables ]]--
local images = {}
local gameData = {}
local lastSelectedIndex = nil
local lastLoadedCount = 0
--[[ Event ]]--
this.OnNewGameSelected = Utility.Signal()
-- we need to fetch for description/isFavorited, so we send a late signal to update those
this.OnNewGameSelectedLate = Utility.Signal()
--[[ Private Functions ]]--
local function insertSortData(page)
if not page then
print("Error: SortCarousel failed to get a valid page for insertSortData.")
return
end
-- TODO: Get new square icons
local ids = page:GetPagePlaceIds()
local names = page:GetPagePlaceNames()
local voteData = page:GetPageVoteData()
local iconIds = page:GetPageIconIds()
local creatorNames = page:GetCreatorNames()
--
for i = 1, #page.Data do
local entry = {
Name = names[i];
PlaceId = ids[i];
IconId = iconIds[i];
VoteData = voteData[i];
CreatorName = creatorNames[i];
-- Description/IsFavorited needs to be queried for each game, do it only when needed
-- we'll also cache gameData
Description = nil;
IsFavorited = nil;
GameData = nil;
}
gameData[#gameData + 1] = entry
end
lastLoadedCount = #gameData
end
local function createCarouselImages()
local thumbSize = ThumbnailLoader.Sizes.Medium
local assetType = ThumbnailLoader.AssetType.Icon
for i = 1, IMAGE_COUNT do
local data = gameData[i]
if data then
local image = Utility.Create'ImageButton'
{
Name = "GameImage";
BorderSizePixel = 0;
BackgroundColor3 = GlobalSettings.GreyButtonColor;
ZIndex = 2;
SoundManager:CreateSound('MoveSelection');
AssetManager.CreateShadow(1);
}
local thumbLoader = ThumbnailLoader:Create(image, data.IconId, thumbSize, assetType)
spawn(function()
if not thumbLoader:LoadAsync() then
-- TODO
end
end)
table.insert(images, image)
carousel:AddItem(image)
-- connect button press based on current selected index mapped to gameData
image.MouseButton1Click:connect(function()
if lastSelectedIndex and gameData[lastSelectedIndex] then
local currentData = gameData[lastSelectedIndex]
EventHub:dispatchEvent(EventHub.Notifications["OpenGameDetail"], currentData.PlaceId,
currentData.Name, currentData.IconId, currentData.GameData)
end
end)
end
end
end
--[[ Event Connections ]]--
local nextLoadIndex = 0
local lastSelectedObject = nil
local onNewFocusCn = nil
local function onNewFocusItem(newIndex, isRight, selectedObject)
lastSelectedObject = selectedObject
lastSelectedIndex = newIndex
--
if gameData[newIndex] then
local currentData = gameData[newIndex]
if this then
this.OnNewGameSelected:fire(currentData)
end
-- description/isFavorited needs to fetch, so send a late update
spawn(function()
if not currentData.GameData then
local gameData = GameDataModule:GetGameDataAsync(currentData.PlaceId)
if gameData then
currentData.GameData = gameData
currentData.Description = gameData:GetDescription()
currentData.IsFavorited = gameData:GetIsFavoritedByUser()
end
end
if this and selectedObject == lastSelectedObject then
this.OnNewGameSelectedLate:fire(currentData.Description, currentData.IsFavorited)
end
end)
end
-- load more data
if isRight and #gameData > IMAGE_COUNT and newIndex == nextLoadIndex then
nextLoadIndex = nextLoadIndex + LOAD_COUNT
local page = gameCollection:GetSortAsync(lastLoadedCount, LOAD_COUNT)
insertSortData(page)
carousel:SetMaxItems(#gameData)
end
end
onNewFocusCn = carousel.OnNewFocusItem:connect(onNewFocusItem)
--[[ Public API ]]--
function this:SetParent(newParent)
carousel:SetParent(newParent)
end
function this:GetCurrentSelectedGameData()
if gameData[lastSelectedIndex] then
return gameData[lastSelectedIndex]
end
end
function this:GetItemAt(index)
return images[index]
end
function this:Destroy()
carousel:Destroy()
if onNewFocusCn then
onNewFocusCn:disconnect()
onNewFocusCn = nil
end
spawn(function()
gameData = nil
this = nil
end)
end
function this:LoadSortAsync()
local loader = LoadingWidget(
{ Parent = parent },{
function()
local page = gameCollection:GetSortAsync(0, LOAD_COUNT)
insertSortData(page)
createCarouselImages()
if carousel then
carousel:SetDataTable(gameData)
carousel:SetMaxItems(#gameData)
carousel:SetFocusPosition(1)
onNewFocusItem(1, nil, images[1])
nextLoadIndex = LOAD_COUNT / 2
end
end
})
loader:AwaitFinished()
loader:Cleanup()
loader = nil
end
return this
end
return createSortCarousel