add gs
This commit is contained in:
@@ -0,0 +1,706 @@
|
||||
-- Written by Kip Turner and Bo Zhang, Copyright Roblox 2017
|
||||
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local GuiService = game:GetService('GuiService')
|
||||
local RunService = game:GetService('RunService')
|
||||
|
||||
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
|
||||
local Modules = GuiRoot:FindFirstChild("Modules")
|
||||
local ShellModules = Modules:FindFirstChild("Shell")
|
||||
|
||||
local PackageData = require(ShellModules:FindFirstChild('PackageData'))
|
||||
local ScrollingGridModule = require(ShellModules:FindFirstChild('ScrollingGrid'))
|
||||
local AvatarTile = require(ShellModules:FindFirstChild('AvatarTile'))
|
||||
local Utility = require(ShellModules:FindFirstChild('Utility'))
|
||||
local ScreenManager = require(ShellModules:FindFirstChild('ScreenManager'))
|
||||
local GlobalSettings = require(ShellModules:FindFirstChild('GlobalSettings'))
|
||||
local LoadingWidget = require(ShellModules:FindFirstChild('LoadingWidget'))
|
||||
local ThumbnailLoader = require(ShellModules:FindFirstChild('ThumbnailLoader'))
|
||||
|
||||
local Analytics = require(ShellModules:FindFirstChild('Analytics'))
|
||||
local Strings = require(ShellModules:FindFirstChild('LocalizedStrings'))
|
||||
local SoundManager = require(ShellModules:FindFirstChild('SoundManager'))
|
||||
|
||||
local HintActionView = require(ShellModules:FindFirstChild('HintActionView'))
|
||||
local XboxAppState = require(ShellModules:FindFirstChild('AppState'))
|
||||
|
||||
local GLOW_BASE_RPM = 2
|
||||
local GLOW_TOP_RPM = -0.5
|
||||
local GLOW_TRANSPARENCY = 0.2
|
||||
local CATALOG_BELOW_POSITION = 320
|
||||
|
||||
|
||||
local function CreateAvatarPane(parent)
|
||||
local this = {}
|
||||
|
||||
local inFocus = false
|
||||
local isShown = false
|
||||
|
||||
local AvatarObjects = {}
|
||||
|
||||
local OnGuiServiceChangedConn = nil
|
||||
|
||||
local lastParent = parent
|
||||
|
||||
|
||||
local MainContainer = Utility.Create'Frame'
|
||||
{
|
||||
Name = 'AvatarPane';
|
||||
Size = UDim2.new(1, 0, 1, 0);
|
||||
BackgroundTransparency = 1;
|
||||
Visible = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
local MyAvatarContainer = Utility.Create'Frame'
|
||||
{
|
||||
Name = 'MyAvatarContainer';
|
||||
Size = UDim2.new(0.38,0,1,0);
|
||||
Position = UDim2.new(0,0,0,0);
|
||||
BackgroundTransparency = 1;
|
||||
ClipsDescendants = true;
|
||||
Parent = MainContainer;
|
||||
}
|
||||
local MyNameLabel = Utility.Create'TextLabel'
|
||||
{
|
||||
Name = 'MyNameLabel';
|
||||
Text = '';
|
||||
Size = UDim2.new(1,0,0,25);
|
||||
Position = UDim2.new(0,12,0,0);
|
||||
TextXAlignment = 'Left';
|
||||
TextColor3 = GlobalSettings.WhiteTextColor;
|
||||
Font = GlobalSettings.RegularFont;
|
||||
FontSize = GlobalSettings.SubHeaderSize;
|
||||
BackgroundTransparency = 1;
|
||||
Parent = MyAvatarContainer;
|
||||
};
|
||||
local ProfileImageContainer = Utility.Create'Frame'
|
||||
{
|
||||
Name = 'ProfileImageContainer';
|
||||
Size = UDim2.new(0.68,0,0.9,-MyNameLabel.Size.Y.Offset);
|
||||
Position = UDim2.new(0.16, 0, 0.05, MyNameLabel.Size.Y.Offset);
|
||||
BackgroundTransparency = 1;
|
||||
Parent = MyAvatarContainer;
|
||||
}
|
||||
local ProfileImage = Utility.Create'ImageLabel'
|
||||
{
|
||||
Name = 'ProfileImage';
|
||||
Size = UDim2.new(0,780,0,780);
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0);
|
||||
BackgroundTransparency = 1;
|
||||
ZIndex = 3;
|
||||
Parent = ProfileImageContainer;
|
||||
};
|
||||
local CrossfadeProfileImage = Utility.Create'ImageLabel'
|
||||
{
|
||||
Name = 'CrossfadeProfileImage';
|
||||
Size = UDim2.new(1,0,1,0);
|
||||
Position = UDim2.new(0, 0, 0, 0);
|
||||
BackgroundTransparency = 1;
|
||||
ImageTransparency = 1;
|
||||
ZIndex = 3;
|
||||
Parent = ProfileImage;
|
||||
};
|
||||
local CharacterGlowBase = Utility.Create'ImageLabel'
|
||||
{
|
||||
Name = 'CharacterGlowBase';
|
||||
Size = UDim2.new(0,1015,0,1002);
|
||||
BackgroundTransparency = 1;
|
||||
Image = 'rbxasset://textures/ui/Shell/Images/CharacterGlow/CharacterGlowBase.png';
|
||||
ImageTransparency = GLOW_TRANSPARENCY;
|
||||
Parent = CrossfadeProfileImage;
|
||||
AnchorPoint = Vector2.new(0.5, 0.5);
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0);
|
||||
};
|
||||
local CharacterGlowTop = Utility.Create'ImageLabel'
|
||||
{
|
||||
Name = 'CharacterGlowTop';
|
||||
Size = UDim2.new(0,1026,0,1009);
|
||||
BackgroundTransparency = 1;
|
||||
Image = 'rbxasset://textures/ui/Shell/Images/CharacterGlow/CharacterGlowTop.png';
|
||||
ImageTransparency = GLOW_TRANSPARENCY;
|
||||
ZIndex = 2;
|
||||
Parent = CrossfadeProfileImage;
|
||||
AnchorPoint = Vector2.new(0.5, 0.5);
|
||||
Position = UDim2.new(0.5, 0, 0.5, 0);
|
||||
};
|
||||
local function onSizeChanged()
|
||||
ProfileImage.Size = Utility.CalculateFill(ProfileImage, ThumbnailLoader.AvatarSizes.Size352x352)
|
||||
ProfileImage.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
ProfileImage.Position = UDim2.new(0.5, 0, 0.5, 0)
|
||||
end
|
||||
|
||||
-- Hint Action View
|
||||
local hintActionView = HintActionView(nil, "AvatarPaneSelectAction")
|
||||
hintActionView:SetImage('rbxasset://textures/ui/Shell/ButtonIcons/XButton.png')
|
||||
hintActionView:SetText(Strings:LocalizedString('EquipWord'))
|
||||
hintActionView:SetTransparency(1)
|
||||
hintActionView:SetParent(lastParent.Parent) -- this assumes parent is HubContainer from AppHub.lua
|
||||
|
||||
local function UpdateEquipButton(IsOwned, IsWearing)
|
||||
hintActionView:SetVisibleWithTween( (IsOwned and not IsWearing) and 0 or 1)
|
||||
end
|
||||
|
||||
local SelectableAvatarsContainer = Utility.Create'Frame'
|
||||
{
|
||||
Name = 'SelectableAvatarsContainer';
|
||||
Size = UDim2.new(0.6,0,1,0);
|
||||
Position = UDim2.new(0.4,0,0,0);
|
||||
BackgroundTransparency = 1;
|
||||
Parent = MainContainer;
|
||||
}
|
||||
|
||||
local NoCatalogStatusMessage = Utility.Create'TextLabel'
|
||||
{
|
||||
Name = 'NoCatalogStatusMessage';
|
||||
Text = Strings:LocalizedString('DefaultErrorPhrase');
|
||||
Size = UDim2.new(0.9,0,1,-125);
|
||||
Position = UDim2.new(0.05, 0, 0, 0);
|
||||
TextColor3 = GlobalSettings.GreyTextColor;
|
||||
TextWrapped = true;
|
||||
TextTransparency = GlobalSettings.FriendStatusTextTransparency;
|
||||
Font = GlobalSettings.BoldFont;
|
||||
FontSize = GlobalSettings.DescriptionSize;
|
||||
BackgroundTransparency = 1;
|
||||
Visible = false;
|
||||
Parent = SelectableAvatarsContainer;
|
||||
};
|
||||
|
||||
local MyCollectionTitle = Utility.Create'TextLabel'
|
||||
{
|
||||
Name = 'MyCollectionTitle';
|
||||
Text = Strings:LocalizedString('AvatarOutfitsTitle');
|
||||
Size = UDim2.new(1,0,0,40);
|
||||
TextXAlignment = 'Left';
|
||||
TextColor3 = GlobalSettings.WhiteTextColor;
|
||||
Font = GlobalSettings.RegularFont;
|
||||
FontSize = GlobalSettings.SubHeaderSize;
|
||||
BackgroundTransparency = 1;
|
||||
Visible = false;
|
||||
Parent = SelectableAvatarsContainer;
|
||||
};
|
||||
|
||||
local MyCollectionScroller = ScrollingGridModule()
|
||||
MyCollectionScroller:SetSize(UDim2.new(1,0,1,-MyCollectionTitle.Size.Y.Offset - 40))
|
||||
MyCollectionScroller:SetScrollDirection(MyCollectionScroller.Enum.ScrollDirection.Horizontal)
|
||||
MyCollectionScroller:SetCellSize(Vector2.new(220, 220))
|
||||
MyCollectionScroller:SetSpacing(Vector2.new(25,25))
|
||||
MyCollectionScroller:SetPosition(UDim2.new(0,0,0,MyCollectionTitle.Size.Y.Offset))
|
||||
MyCollectionScroller:SetRowColumnConstraint(1)
|
||||
-- MyCollectionScroller:SetParent(SelectableAvatarsContainer)
|
||||
|
||||
local CatalogTitle = Utility.Create'TextLabel'
|
||||
{
|
||||
Name = 'CatalogTitle';
|
||||
Text = Strings:LocalizedString('AvatarCatalogTitle');
|
||||
Size = UDim2.new(1,0,0,40);
|
||||
Position = UDim2.new(0,0,0,0);
|
||||
TextXAlignment = 'Left';
|
||||
TextColor3 = GlobalSettings.WhiteTextColor;
|
||||
Font = GlobalSettings.RegularFont;
|
||||
FontSize = GlobalSettings.SubHeaderSize;
|
||||
BackgroundTransparency = 1;
|
||||
Parent = SelectableAvatarsContainer;
|
||||
};
|
||||
|
||||
local AvatarScroller = ScrollingGridModule()
|
||||
AvatarScroller:SetSize(UDim2.new(1,0,1,-CatalogTitle.Size.Y.Offset - 40))
|
||||
AvatarScroller:SetScrollDirection(AvatarScroller.Enum.ScrollDirection.Horizontal)
|
||||
AvatarScroller:SetCellSize(Vector2.new(220, 220))
|
||||
AvatarScroller:SetPosition(UDim2.new(0,0,0,40))
|
||||
AvatarScroller:SetSpacing(Vector2.new(25,25))
|
||||
AvatarScroller:SetRowColumnConstraint(2)
|
||||
AvatarScroller:SetParent(SelectableAvatarsContainer)
|
||||
|
||||
local function SortMyCollectionScroller()
|
||||
MyCollectionScroller:SortItems(
|
||||
function(a, b)
|
||||
local aObject = a and AvatarObjects[a] and AvatarObjects[a]:GetPackageInfo()
|
||||
local bObject = b and AvatarObjects[b] and AvatarObjects[b]:GetPackageInfo()
|
||||
local aIsEquipped = aObject and aObject:IsWearing()
|
||||
local bIsEquipped = bObject and bObject:IsWearing()
|
||||
local aName = aObject and aObject:GetName()
|
||||
local bName = bObject and bObject:GetName()
|
||||
|
||||
if aIsEquipped then return true elseif bIsEquipped then return false end
|
||||
if aName and bName then
|
||||
return aName < bName
|
||||
end
|
||||
return aObject ~= nil
|
||||
end)
|
||||
end
|
||||
|
||||
--if all avatars owned, MyCollection should be 2 rows and catalog should be hidden
|
||||
local function CheckAllAvatarsOwned()
|
||||
if #AvatarScroller.GridItems == 0 then
|
||||
MyCollectionScroller:SetRowColumnConstraint(2)
|
||||
CatalogTitle.Visible = false
|
||||
AvatarScroller.Visible = false
|
||||
AvatarScroller:SetParent(nil)
|
||||
else
|
||||
MyCollectionScroller:SetRowColumnConstraint(1)
|
||||
CatalogTitle.Visible = true
|
||||
AvatarScroller.Visible = true
|
||||
AvatarScroller:SetParent(SelectableAvatarsContainer)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnAddToMyCollectionScroller()
|
||||
CatalogTitle.Position = UDim2.new(0,0,0, CATALOG_BELOW_POSITION)
|
||||
AvatarScroller:SetPosition(UDim2.new(0,0,0,CATALOG_BELOW_POSITION + 40))
|
||||
AvatarScroller:SetRowColumnConstraint(1)
|
||||
MyCollectionTitle.Visible = true
|
||||
MyCollectionScroller:SetParent(SelectableAvatarsContainer)
|
||||
CheckAllAvatarsOwned()
|
||||
SortMyCollectionScroller()
|
||||
end
|
||||
|
||||
local LoaderSpinner = nil
|
||||
local GlobalFadeCount = 1
|
||||
local function CrossfadeAvatarImage(frontImage, fadeImage, imageSource, duration)
|
||||
if not imageSource then return end
|
||||
duration = duration or 0.75
|
||||
|
||||
GlobalFadeCount = GlobalFadeCount + 1
|
||||
local thisFadeCount = GlobalFadeCount
|
||||
local fadeoutDuration = duration
|
||||
|
||||
spawn(function()
|
||||
local dummyImage = nil
|
||||
if LoaderSpinner then
|
||||
LoaderSpinner:Cleanup()
|
||||
end
|
||||
|
||||
--If imageSource if a function, then it's maybe a async call to get new image and we show the loaderspinner.
|
||||
--Otherwise, if the imageSource is a valid new image, we just do the Crossfade (without the spinner)
|
||||
if type(imageSource) == 'function' then
|
||||
local newLoaderSpinner = LoadingWidget({Parent = frontImage, ZIndex = 3}, {
|
||||
function() dummyImage = imageSource() end
|
||||
})
|
||||
LoaderSpinner = newLoaderSpinner
|
||||
newLoaderSpinner:AwaitFinished()
|
||||
newLoaderSpinner:Cleanup()
|
||||
elseif type(imageSource) == 'table' and imageSource.Image then
|
||||
dummyImage = imageSource
|
||||
end
|
||||
|
||||
if thisFadeCount == GlobalFadeCount then
|
||||
--Avoid updating with same image
|
||||
if dummyImage and frontImage and dummyImage.Image ~= frontImage.Image then
|
||||
local noPreviousImage = (frontImage.Image == "" and fadeImage.Image == "")
|
||||
if noPreviousImage then
|
||||
fadeoutDuration = 0
|
||||
else
|
||||
fadeImage.Image = frontImage.Image
|
||||
end
|
||||
|
||||
|
||||
Utility.PropertyTweener(fadeImage, 'ImageTransparency', noPreviousImage and 0 or frontImage.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
|
||||
Utility.PropertyTweener(CharacterGlowBase, 'ImageTransparency', CharacterGlowBase.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
|
||||
Utility.PropertyTweener(CharacterGlowTop, 'ImageTransparency', CharacterGlowTop.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
|
||||
frontImage.ImageTransparency = 1
|
||||
|
||||
frontImage.Image = dummyImage.Image
|
||||
|
||||
Utility.PropertyTweener(frontImage, 'ImageTransparency', frontImage.ImageTransparency, 0, duration, Utility.EaseInOutQuad, true)
|
||||
Utility.PropertyTweener(CharacterGlowBase, 'ImageTransparency', CharacterGlowBase.ImageTransparency, GLOW_TRANSPARENCY, duration, Utility.EaseInOutQuad, true)
|
||||
Utility.PropertyTweener(CharacterGlowTop, 'ImageTransparency', CharacterGlowTop.ImageTransparency, GLOW_TRANSPARENCY, duration, Utility.EaseInOutQuad, true)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function UpdateProfileImage(imageSource)
|
||||
MyNameLabel.Text = XboxAppState.store:getState().XboxUser.gamertag
|
||||
CrossfadeAvatarImage(ProfileImage, CrossfadeProfileImage, imageSource)
|
||||
end
|
||||
|
||||
local function onOwnershipChanged(tile, nowOwns)
|
||||
-- Move purchased packages into my MyCollection
|
||||
if nowOwns then
|
||||
local guiObject = tile and tile:GetGuiObject()
|
||||
if guiObject and AvatarScroller:ContainsItem(guiObject) then
|
||||
AvatarScroller:RemoveItem(guiObject)
|
||||
MyCollectionScroller:AddItem(guiObject)
|
||||
OnAddToMyCollectionScroller()
|
||||
if inFocus then
|
||||
GuiService.SelectedCoreObject = guiObject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ownershipChangedCns = {}
|
||||
|
||||
local function listenToOwnershipChanged(tile)
|
||||
local packageInfo = tile and tile:GetPackageInfo()
|
||||
if packageInfo and not packageInfo:IsOwned() and (packageInfo.OwnershipChanged ~= nil) then
|
||||
if not ownershipChangedCns[tile] then
|
||||
ownershipChangedCns[tile] = packageInfo.OwnershipChanged:connect(function(nowOwns)
|
||||
onOwnershipChanged(tile, nowOwns)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function removeListenToOwnershipChanged(tile)
|
||||
if ownershipChangedCns[tile] then
|
||||
ownershipChangedCns[tile]:disconnect()
|
||||
ownershipChangedCns[tile] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function onEquipChanged()
|
||||
local selectedObject = GuiService.SelectedCoreObject
|
||||
|
||||
if AvatarObjects[selectedObject] then
|
||||
local packageInfo = AvatarObjects[selectedObject]:GetPackageInfo()
|
||||
if packageInfo then
|
||||
UpdateEquipButton(packageInfo:IsOwned(), packageInfo:IsWearing())
|
||||
end
|
||||
else
|
||||
-- user can select avatar tab button
|
||||
UpdateEquipButton(false, false)
|
||||
end
|
||||
SortMyCollectionScroller()
|
||||
end
|
||||
|
||||
local lastSelectedObject = GuiService.SelectedCoreObject
|
||||
local function OnSelectedCoreObjectChanged()
|
||||
local selectedObject = GuiService.SelectedCoreObject
|
||||
|
||||
if AvatarObjects[lastSelectedObject] then
|
||||
AvatarObjects[lastSelectedObject]:RemoveFocus()
|
||||
end
|
||||
if AvatarObjects[selectedObject] then
|
||||
AvatarObjects[selectedObject]:Focus()
|
||||
lastSelectedObject = selectedObject
|
||||
end
|
||||
onEquipChanged()
|
||||
end
|
||||
|
||||
|
||||
function this:GetDefaultSelectableObject()
|
||||
if MyCollectionScroller:GetFirstVisibleItem() then
|
||||
return MyCollectionScroller:GetFirstVisibleItem()
|
||||
end
|
||||
if AvatarScroller:GetFirstVisibleItem() then
|
||||
return AvatarScroller:GetFirstVisibleItem()
|
||||
end
|
||||
|
||||
--In case GetFirstVisibleItem breaks
|
||||
if MyCollectionScroller.GridItems[1] then
|
||||
return MyCollectionScroller.GridItems[1]
|
||||
end
|
||||
if AvatarScroller.GridItems[1] then
|
||||
return AvatarScroller.GridItems[1]
|
||||
end
|
||||
end
|
||||
|
||||
local packagesData = nil
|
||||
local packagesDataConns = {}
|
||||
local AvatarWebDataInitializeLoader = nil
|
||||
local function removeListenToPackagesDataUpdate()
|
||||
for _, conn in pairs(packagesDataConns) do
|
||||
conn:disconnect()
|
||||
end
|
||||
packagesDataConns = {}
|
||||
end
|
||||
|
||||
local function listenToPackagesDataUpdate()
|
||||
if packagesData and packagesDataConns then
|
||||
table.insert(packagesDataConns, packagesData.OnDifferentWearing:connect(function(assetId) onEquipChanged() end))
|
||||
table.insert(packagesDataConns, packagesData.OnDifferentOwned:connect(function(assetId, owned) onEquipChanged() end))
|
||||
table.insert(packagesDataConns, packagesData.OnProfileImageUpdateEnd:connect(function(newProfileImage)
|
||||
UpdateProfileImage(newProfileImage)
|
||||
end))
|
||||
table.insert(packagesDataConns, packagesData.OnProfileImageUpdateBegin:connect(function()
|
||||
UpdateProfileImage(function()
|
||||
return packagesData.OnProfileImageUpdateEnd.wait()
|
||||
end)
|
||||
end))
|
||||
end
|
||||
end
|
||||
|
||||
local function LoadAvatarWebData()
|
||||
local function clearCatalogPackages()
|
||||
AvatarScroller:RemoveAllItems()
|
||||
MyCollectionScroller:RemoveAllItems()
|
||||
for k,_ in pairs(AvatarObjects) do
|
||||
AvatarObjects[k] = nil
|
||||
end
|
||||
AvatarObjects = {}
|
||||
end
|
||||
|
||||
local function loadCatalogPackages(packages)
|
||||
clearCatalogPackages()
|
||||
if packages then
|
||||
for _, packageInfo in pairs(packages) do
|
||||
local avatarItemContainer = AvatarTile(packageInfo)
|
||||
|
||||
AvatarObjects[avatarItemContainer:GetGuiObject()] = avatarItemContainer
|
||||
|
||||
if packageInfo:IsOwned() then
|
||||
MyCollectionScroller:AddItem(avatarItemContainer:GetGuiObject())
|
||||
OnAddToMyCollectionScroller()
|
||||
else
|
||||
AvatarScroller:AddItem(avatarItemContainer:GetGuiObject())
|
||||
listenToOwnershipChanged(avatarItemContainer)
|
||||
end
|
||||
|
||||
if isShown then
|
||||
avatarItemContainer:Show()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Wait until initialize is done
|
||||
if AvatarWebDataInitializeLoader then return end
|
||||
|
||||
if PackageData:HasCachedData() then --Sync process to get and update packagesData, no spinner
|
||||
local prevVersion = packagesData and packagesData.Version or nil
|
||||
packagesData = PackageData:GetCachedData()
|
||||
--If init or packagesData got updated
|
||||
if not prevVersion or prevVersion ~= packagesData.Version then
|
||||
SelectableAvatarsContainer.Visible = false
|
||||
UpdateProfileImage(packagesData.ProfileImage.Data)
|
||||
loadCatalogPackages(packagesData.Packages.Data)
|
||||
SelectableAvatarsContainer.Visible = true
|
||||
removeListenToPackagesDataUpdate()
|
||||
listenToPackagesDataUpdate()
|
||||
end
|
||||
else --Async process to get and update packagesData, show spinner
|
||||
SelectableAvatarsContainer.Visible = false
|
||||
local containerSize = SelectableAvatarsContainer.Size
|
||||
AvatarWebDataInitializeLoader = LoadingWidget(
|
||||
{Parent = MainContainer, Position = SelectableAvatarsContainer.Position + UDim2.new(containerSize.X.Scale / 2, containerSize.X.Offset / 2, containerSize.Y.Scale / 2, containerSize.Y.Offset / 2)},
|
||||
{function()
|
||||
packagesData = PackageData:GetCachedData()
|
||||
if packagesData and packagesData.Packages then
|
||||
loadCatalogPackages(packagesData.Packages.Data)
|
||||
end
|
||||
end}
|
||||
)
|
||||
spawn(function()
|
||||
NoCatalogStatusMessage.Visible = false
|
||||
|
||||
UpdateProfileImage(function()
|
||||
if AvatarWebDataInitializeLoader then
|
||||
AvatarWebDataInitializeLoader:AwaitFinished()
|
||||
end
|
||||
if packagesData and packagesData.ProfileImage then
|
||||
return packagesData.ProfileImage.Data
|
||||
end
|
||||
end)
|
||||
|
||||
AvatarWebDataInitializeLoader:AwaitFinished()
|
||||
AvatarWebDataInitializeLoader:Cleanup()
|
||||
AvatarWebDataInitializeLoader = nil
|
||||
SelectableAvatarsContainer.Visible = true
|
||||
removeListenToPackagesDataUpdate()
|
||||
|
||||
if not packagesData then
|
||||
NoCatalogStatusMessage.Visible = true
|
||||
end
|
||||
|
||||
--Hook connections if the pane is still visible after loading
|
||||
if isShown then
|
||||
listenToPackagesDataUpdate()
|
||||
end
|
||||
|
||||
if inFocus and isShown and GuiService.SelectedCoreObject == nil then
|
||||
GuiService.SelectedCoreObject = this:GetDefaultSelectableObject()
|
||||
end
|
||||
|
||||
if this.TransitionTweens == nil or #this.TransitionTweens == 0 then
|
||||
this.TransitionTweens = ScreenManager:FadeInSitu(SelectableAvatarsContainer)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
LoadAvatarWebData()
|
||||
|
||||
--[[ Public API ]]--
|
||||
function this:GetName()
|
||||
return Strings:LocalizedString('AvatarWord')
|
||||
end
|
||||
|
||||
function this:GetAnalyticsInfo()
|
||||
return {[Analytics.WidgetNames('WidgetId')] = Analytics.WidgetNames('AvatarPaneId')}
|
||||
end
|
||||
|
||||
function this:IsFocused()
|
||||
return inFocus
|
||||
end
|
||||
|
||||
local debounceSelect = false
|
||||
function this:OnSelectAction()
|
||||
if debounceSelect then return end
|
||||
debounceSelect = true
|
||||
|
||||
local selectedObject = GuiService.SelectedCoreObject
|
||||
if selectedObject and AvatarObjects[selectedObject] then
|
||||
if AvatarObjects[selectedObject]:Select() then
|
||||
SoundManager:Play('ButtonPress')
|
||||
end
|
||||
end
|
||||
|
||||
debounceSelect = false
|
||||
end
|
||||
|
||||
function this:OpenEquippedPackage()
|
||||
if isShown and inFocus then
|
||||
for _, avatarItemContainer in pairs(AvatarObjects) do
|
||||
local packageInfo = avatarItemContainer:GetPackageInfo()
|
||||
if packageInfo then
|
||||
if packageInfo:IsWearing() then
|
||||
avatarItemContainer:OnClick()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--[[ End Public API ]]--
|
||||
|
||||
local profileImageChangeCn = nil
|
||||
function this:Show()
|
||||
isShown = true
|
||||
|
||||
Utility.DisconnectEvent(profileImageChangeCn)
|
||||
profileImageChangeCn = ProfileImageContainer:GetPropertyChangedSignal('AbsoluteSize'):connect(function()
|
||||
onSizeChanged()
|
||||
end)
|
||||
onSizeChanged()
|
||||
|
||||
local lastUpdate = tick()
|
||||
RunService:BindToRenderStep("UpdateAvatarGlow", Enum.RenderPriority.Camera.Value,
|
||||
function()
|
||||
local now = tick()
|
||||
local delta = now - lastUpdate
|
||||
|
||||
CharacterGlowBase.Rotation = CharacterGlowBase.Rotation + delta * GLOW_BASE_RPM * 6 -- 6 = 360 / 60
|
||||
CharacterGlowTop.Rotation = CharacterGlowTop.Rotation + delta * GLOW_TOP_RPM * 6
|
||||
|
||||
lastUpdate = now
|
||||
end)
|
||||
|
||||
if packagesData then
|
||||
listenToPackagesDataUpdate()
|
||||
UpdateProfileImage(packagesData.ProfileImage.Data)
|
||||
end
|
||||
LoadAvatarWebData()
|
||||
|
||||
for _, avatarItemContainer in pairs(AvatarObjects) do
|
||||
avatarItemContainer:Show()
|
||||
listenToOwnershipChanged(avatarItemContainer)
|
||||
local packageInfo = avatarItemContainer and avatarItemContainer:GetPackageInfo()
|
||||
if packageInfo then
|
||||
onOwnershipChanged(avatarItemContainer, packageInfo:IsOwned())
|
||||
end
|
||||
end
|
||||
|
||||
local seenXButtonPressed = false
|
||||
local seenXSelectedObject = nil
|
||||
local function onSelectAvatar(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
seenXButtonPressed = true
|
||||
seenXSelectedObject = GuiService.SelectedCoreObject
|
||||
elseif inputState == Enum.UserInputState.End and seenXButtonPressed then
|
||||
if seenXSelectedObject and seenXSelectedObject == GuiService.SelectedCoreObject then
|
||||
self:OnSelectAction()
|
||||
end
|
||||
seenXButtonPressed = false
|
||||
seenXSelectedObject = nil
|
||||
end
|
||||
end
|
||||
|
||||
hintActionView:BindAction(onSelectAvatar, Enum.KeyCode.ButtonX)
|
||||
|
||||
self.TransitionTweens = ScreenManager:DefaultFadeIn(MainContainer)
|
||||
|
||||
SortMyCollectionScroller()
|
||||
|
||||
MainContainer.Parent = lastParent
|
||||
MainContainer.Visible = true
|
||||
ScreenManager:PlayDefaultOpenSound()
|
||||
end
|
||||
|
||||
|
||||
function this:Hide()
|
||||
isShown = false
|
||||
MainContainer.Visible = false
|
||||
removeListenToPackagesDataUpdate()
|
||||
|
||||
profileImageChangeCn = Utility.DisconnectEvent(profileImageChangeCn)
|
||||
|
||||
RunService:UnbindFromRenderStep("UpdateAvatarGlow")
|
||||
hintActionView:UnbindAction()
|
||||
hintActionView:SetTransparency(1)
|
||||
|
||||
for _, avatarItemContainer in pairs(AvatarObjects) do
|
||||
avatarItemContainer:Hide()
|
||||
removeListenToOwnershipChanged(avatarItemContainer)
|
||||
end
|
||||
|
||||
ScreenManager:DefaultCancelFade(self.TransitionTweens)
|
||||
self.TransitionTweens = nil
|
||||
-- Clean out saved selected object so when we tab back
|
||||
-- we will start with the default selection
|
||||
lastSelectedObject = nil
|
||||
self.SavedSelectObject = nil
|
||||
end
|
||||
|
||||
function this:Focus()
|
||||
inFocus = true
|
||||
|
||||
Utility.DisconnectEvent(OnGuiServiceChangedConn)
|
||||
OnGuiServiceChangedConn = GuiService:GetPropertyChangedSignal('SelectedCoreObject'):connect(function()
|
||||
OnSelectedCoreObjectChanged()
|
||||
end)
|
||||
|
||||
if self.SavedSelectObject and self.SavedSelectObject:IsDescendantOf(MainContainer) then
|
||||
GuiService.SelectedCoreObject = self.SavedSelectObject
|
||||
else
|
||||
local defaultSelection = self:GetDefaultSelectableObject()
|
||||
if defaultSelection then
|
||||
GuiService.SelectedCoreObject = defaultSelection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function this:RemoveFocus()
|
||||
inFocus = false
|
||||
--Remove Focus on AvatarObjects
|
||||
if AvatarObjects and AvatarObjects[lastSelectedObject] then
|
||||
AvatarObjects[lastSelectedObject]:RemoveFocus()
|
||||
end
|
||||
OnGuiServiceChangedConn = Utility.DisconnectEvent(OnGuiServiceChangedConn)
|
||||
|
||||
local selectedObject = GuiService.SelectedCoreObject
|
||||
if isShown then
|
||||
if selectedObject and selectedObject:IsDescendantOf(MainContainer) then
|
||||
self.SavedSelectObject = GuiService.SelectedCoreObject
|
||||
GuiService.SelectedCoreObject = nil
|
||||
else
|
||||
self.SavedSelectObject = lastSelectedObject
|
||||
end
|
||||
end
|
||||
OnSelectedCoreObjectChanged()
|
||||
end
|
||||
|
||||
function this:SetPosition(newPosition)
|
||||
MainContainer.Position = newPosition
|
||||
end
|
||||
|
||||
function this:SetParent(newParent)
|
||||
lastParent = newParent
|
||||
MainContainer.Parent = newParent
|
||||
end
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
return CreateAvatarPane
|
||||
Reference in New Issue
Block a user