local CoreGui = game:GetService("CoreGui") local RobloxGui = CoreGui.RobloxGui local Analytics = require(script.Parent.Analytics) local AppState = require(script.Parent.AppState) local GlobalSettings = require(script.Parent.GlobalSettings) local ScreenItem = require(script.Parent.Models.ScreenItem) local SoundManager = require(script.Parent.SoundManager) local Utility = require(script.Parent.Utility) local InsertScreen = require(script.Parent.Actions.InsertScreen) local RemoveScreen = require(script.Parent.Actions.RemoveScreen) local ScreenManager = {} local ScreenMap = {} local ScreenGuis = {[1] = RobloxGui} local function getScreenPriority(screen) local priority = GlobalSettings.DefaultPriority if screen.GetPriority ~= nil then priority = screen:GetPriority() end return priority end local function setRBXEventStream_Screen(screen, status) if screen and type(screen.GetAnalyticsInfo) == "function" then local screenAnalyticsInfo = screen:GetAnalyticsInfo() if type(screenAnalyticsInfo) == "table" and screenAnalyticsInfo[Analytics.WidgetNames('WidgetId')] then screenAnalyticsInfo.Status = status Analytics.SetRBXEventStream("Widget", screenAnalyticsInfo) end end end function ScreenManager:GetScreenGuiByPriority(priority) priority = math.max(1, priority) if not ScreenGuis[priority] then for i = 1, priority do if not ScreenGuis[i] then ScreenGuis[i] = Utility.Create'ScreenGui' { Name = 'AppShell' .. tostring(i); Parent = CoreGui; } end end end return ScreenGuis[priority] end function ScreenManager:OpenScreen(screen, hidePrevious) if hidePrevious == nil then hidePrevious = true end local data = { hidePrevious = hidePrevious, } local id = tostring(screen) ScreenMap[id] = { screen = screen, isShown = false, } local screenItem = ScreenItem.new(id, getScreenPriority(screen), data) AppState.store:dispatch(InsertScreen(screenItem)) end function ScreenManager:CloseCurrent() local screenList = AppState.store:getState().ScreenList local frontScreen = #screenList > 0 and screenList[1] if not frontScreen or not ScreenMap[frontScreen.id] then return end AppState.store:dispatch(RemoveScreen(frontScreen)) end local function handleScreensRemoved(screenList) local currentListToMap = {} for _, item in ipairs(screenList) do currentListToMap[item.id] = true end local idsToRemove = {} for id,_ in pairs(ScreenMap) do if not currentListToMap[id] then table.insert(idsToRemove, id) end end for _, id in ipairs(idsToRemove) do local screenItem = ScreenMap[id] if screenItem then local screen = screenItem.screen screen:RemoveFocus() screen:Hide() if screen.ScreenRemoved then screen:ScreenRemoved() end setRBXEventStream_Screen(screen, "Close") end ScreenMap[id] = nil end end local function handleScreensAdded(screenList) for i = #screenList, 1, -1 do local screenListItem = screenList[i] local screenMapItem = ScreenMap[screenListItem.id] if screenMapItem then local screen = screenMapItem.screen if i > 1 then local doHide = true local prevListItem = screenList[i - 1] if prevListItem and prevListItem.data then doHide = prevListItem.data.hidePrevious end screen:RemoveFocus() if doHide then screen:Hide() screenMapItem.isShown = false end if not screenMapItem.isShown and not doHide then screen:Show() screenMapItem.isShown = true end else if not screenMapItem.isShown then screen:Show() screenMapItem.isShown = true setRBXEventStream_Screen(screen, "Show") end screen:Focus() setRBXEventStream_Screen(screen, "Focus") end end end end local function update(screenList) handleScreensRemoved(screenList) handleScreensAdded(screenList) end AppState.store.changed:connect(function(newState, oldState) local currentScreenList = newState.ScreenList local previousScreenList = oldState.ScreenList if currentScreenList == previousScreenList then return end update(currentScreenList) end) function ScreenManager:ContainsScreen(desiredScreen) for _,item in pairs(ScreenMap) do if item.screen == desiredScreen then return true end end return false end function ScreenManager:GetScreenBelow(screen) local screenList = AppState.store:getState().ScreenList for i,screenItem in ipairs(screenList) do if screenItem.id == tostring(screen) then local prevScreenItem = screenList[i + 1] if prevScreenItem then local prevScreen = ScreenMap[prevScreenItem.id] if prevScreen then return prevScreen.screen end end end end return nil end function ScreenManager:GetTopScreen() local screenList = AppState.store:getState().ScreenList if screenList and #screenList > 0 then local frontScreen = screenList[1] return ScreenMap[frontScreen.id].screen end return nil end ----- TWEENS ----- local function FadeInElement(element, tweeners) if element == nil then return end if element:IsA('ImageLabel') or element:IsA('ImageButton') then table.insert(tweeners, Utility.PropertyTweener(element, 'ImageTransparency', 1, element.ImageTransparency, 0.5, Utility.EaseOutQuad)) end if element:IsA('GuiObject') then table.insert(tweeners, Utility.PropertyTweener(element, 'BackgroundTransparency', 1, element.BackgroundTransparency, 0.5, Utility.EaseOutQuad)) end if element:IsA('TextLabel') or element:IsA('TextBox') or element:IsA('TextButton') then table.insert(tweeners, Utility.PropertyTweener(element, 'TextTransparency', 1, element.TextTransparency, 0.5, Utility.EaseOutQuad)) end for _, child in pairs(element:GetChildren()) do FadeInElement(child, tweeners) end end function ScreenManager:FadeInSitu(guiObject) local tweeners = {} if guiObject then FadeInElement(guiObject, tweeners) end return tweeners end function ScreenManager:DefaultFadeIn(guiObject) local tweeners = {} if guiObject then table.insert(tweeners, Utility.PropertyTweener(guiObject, 'Position', guiObject.Position + UDim2.new(0.15, 0, 0, 0), guiObject.Position, 0.5, function(t,b,c,d) if t >= d then return b + c end t = t / d; local tComputed = t*(t-2) return -UDim2.new(c.X.Scale * tComputed, c.X.Offset * tComputed, c.Y.Scale * tComputed, c.Y.Offset * tComputed) + b end)) FadeInElement(guiObject, tweeners) end return tweeners end function ScreenManager:DefaultCancelFade(tweens) if tweens then for _, tween in pairs(tweens) do tween:Finish() end end return nil end function ScreenManager:PlayDefaultOpenSound() SoundManager:Play('ScreenChange') end return ScreenManager