local H=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local A=H("\083\099\114\101\101\110\067\111\118\101\114\072\101\108\112\101\114\066\117\105\108\100\101\114")local Q=H("\083\105\103\110\097\108")local u=H("\077\097\105\100")local T=H("\080\114\111\109\105\115\101")local V={}V.__index=V V.ClassName="\083\099\114\101\101\110\067\111\118\101\114"V.SQUARE_PADDING=2 function V.new(H)local T=setmetatable({},V)T.Gui=H or error("\078\111 \103\117\105")T.Done=Q.new()T._maid=u.new()T._builder=A.new(H)return T end function V.SetScreenGui(A,H)A._screenGui=H or error("\078\111 \115\099\114\101\101\110\071\117\105")A._maid:GiveTask(A._screenGui)A._maid:GiveTask((A._screenGui:GetPropertyChangedSignal("\065\098\115\111\108\117\116\101\083\105\122\101")):Connect(function()A:_updateSize()end))A:_updateSize()A.Gui.Parent=A._screenGui end function V.Show(A,H)H=H or.6 local Q=A:_getDiagonalSquares(12)A:_showSquares(Q,H)return T.new(A.Done)end function V.Hide(A,H)H=H or.6 local Q=A:_getDiagonalSquares(12)A:_hideSquares(Q,H)return T.new(A.Done)end function V._updateSize(H)assert(H._screenGui)local A=H._screenGui.AbsoluteSize if A.X>A.Y then H.Gui.SizeConstraint=Enum.SizeConstraint.RelativeXX else H.Gui.SizeConstraint=Enum.SizeConstraint.RelativeYY end end function V._getSquareData(A,H)H=H or 10 local Q=1/H local u=UDim2.new(Q,A.SQUARE_PADDING,Q,A.SQUARE_PADDING)local T={}for A=1,H,1 do T[A]={}for V=1,H,1 do T[A][V]={Position=UDim2.new(A/H-Q/2,0,V/H-Q/2,0);Size=u,AnchorPoint=Vector2.new(.5,.5)}end end return T end function V._getDiagonalSquares(A,H)local Q=A:_getSquareData(H)local u={}for H=1,#Q,1 do for A=1,#Q,1 do local T=Q[H][A]local V=((H-1)+(A-1))+1 u[V]=u[V]or{}table.insert(u[V],T)end end return u end function V._showSquares(Q,H,A)local T=u.new()Q._maid.animMaid=T local V=(A/#H)*8 local K=A-V Q.Gui.BackgroundTransparency=1 local x=true T:GiveTask(function()Q.Gui.BackgroundTransparency=0 x=false Q.Done:Fire()end)for A=1,#H,1 do local u=H[A]local h=K*(A/#H)delay(h,function()if not x then return end for H,A in pairs(u)do local u=Q._builder:CreateSquare(A)u.Size=UDim2.new(0,0,0,0)u.Parent=Q.Gui u:TweenSize(A.Size,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,V,true)T:GiveTask(u)end end)end delay(A,function()T:DoCleaning()end)end function V._hideSquares(Q,H,A)local T=u.new()Q._maid.animMaid=T local V=(A/#H)*4 local K=A-V local x={}for A=1,#H,1 do local u={}table.insert(x,u)local V=H[A]for H,A in pairs(V)do local V=Q._builder:CreateSquare(A)V.Size=A.Size V.Parent=Q.Gui table.insert(u,V)T:GiveTask(V)end end Q.Gui.BackgroundTransparency=1 local h=true T:GiveTask(function()h=false Q.Done:Fire()end)for H=1,#x,1 do local A=K*(H/#x)delay(A,function()if not h then return end for H,A in pairs(x[H])do A:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,V,true)end end)end delay(A,function()T:DoCleaning()end)end function V.Destroy(H)H._maid:DoCleaning()H._maid=nil end return V
--- Covers the screen in a satisfying way
-- @classmod ScreenCover

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local ScreenCoverHelperBuilder = require("ScreenCoverHelperBuilder")
local Signal = require("Signal")
local Maid = require("Maid")
local Promise = require("Promise")

local ScreenCover = {}
ScreenCover.__index = ScreenCover
ScreenCover.ClassName = "ScreenCover"
ScreenCover.SQUARE_PADDING = 2 -- Extra pixels to prevent splits

function ScreenCover.new(gui)
	local self = setmetatable({}, ScreenCover)

	self.Gui = gui or error("No gui")
	self.Done = Signal.new()
	self._maid = Maid.new()

	self._builder = ScreenCoverHelperBuilder.new(gui)

	return self
end

function ScreenCover:SetScreenGui(screenGui)
	self._screenGui = screenGui or error("No screenGui")
	self._maid:GiveTask(self._screenGui)
	self._maid:GiveTask(self._screenGui:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
		self:_updateSize()
	end))
	self:_updateSize()

	self.Gui.Parent = self._screenGui
end

function ScreenCover:Show(playbackTime)
	playbackTime = playbackTime or 0.6

	local diagonals = self:_getDiagonalSquares(12)
	self:_showSquares(diagonals, playbackTime)

	return Promise.new(self.Done)
end

function ScreenCover:Hide(playbackTime)
	playbackTime = playbackTime or 0.6

	local diagonals = self:_getDiagonalSquares(12)
	self:_hideSquares(diagonals, playbackTime)

	return Promise.new(self.Done)
end

--- Force size constraint to fill whole screen
function ScreenCover:_updateSize()
	assert(self._screenGui)

	local absoluteSize = self._screenGui.AbsoluteSize
	if absoluteSize.X > absoluteSize.Y then
		self.Gui.SizeConstraint = Enum.SizeConstraint.RelativeXX
	else
		self.Gui.SizeConstraint = Enum.SizeConstraint.RelativeYY
	end
end

function ScreenCover:_getSquareData(squareCount)
	squareCount = squareCount or 10

	local squareSize = 1/squareCount
	local size = UDim2.new(squareSize, self.SQUARE_PADDING, squareSize, self.SQUARE_PADDING)

	local matrix = {}
	for x=1, squareCount do
		matrix[x] = {}
		for y=1, squareCount do
			matrix[x][y] = {
				Position = UDim2.new(x/squareCount - squareSize/2, 0, y/squareCount - squareSize/2, 0);
				Size = size;
				AnchorPoint = Vector2.new(0.5, 0.5)
			}
		end
	end

	return matrix
end

function ScreenCover:_getDiagonalSquares(squareCount)
	local matrix = self:_getSquareData(squareCount)

	local squares = {} -- Array of arrays

	for x=1, #matrix do
		for y=1, #matrix do
			local square = matrix[x][y]
			local index = (x-1)+(y-1)+1
			squares[index] = squares[index] or {}
			table.insert(squares[index], square)
		end
	end

	return squares
end

function ScreenCover:_showSquares(squareDataList, playbackTime)
	local maid = Maid.new()
	self._maid.animMaid = maid

	local tweenTime = playbackTime/(#squareDataList)*8
	local squarePlaybackTime = (playbackTime - tweenTime)

	self.Gui.BackgroundTransparency = 1
	local alive = true
	maid:GiveTask(function()
		self.Gui.BackgroundTransparency = 0
		alive = false
		self.Done:Fire()
	end)

	for i=1, #squareDataList do
		local dataList = squareDataList[i]
		local delayTime = squarePlaybackTime*(i/#squareDataList)
		delay(delayTime, function()
			if not alive then
				return
			end

			for _, squareData in pairs(dataList) do
				local frame = self._builder:CreateSquare(squareData)
				frame.Size = UDim2.new(0, 0, 0, 0)
				frame.Parent = self.Gui

				frame:TweenSize(squareData.Size, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, tweenTime, true)
				maid:GiveTask(frame)
			end
		end)
	end

	delay(playbackTime, function()
		maid:DoCleaning()
	end)
end

function ScreenCover:_hideSquares(squareDataList, playbackTime)
	local maid = Maid.new()
	self._maid.animMaid = maid

	local tweenTime = playbackTime/(#squareDataList)*4
	local squarePlaybackTime = (playbackTime - tweenTime)

	-- Build squares
	local frameList = {}
	for i=1, #squareDataList do
		local frames = {}
		table.insert(frameList, frames)

		local dataList = squareDataList[i]
		for _, squareData in pairs(dataList) do
			local frame = self._builder:CreateSquare(squareData)
			frame.Size = squareData.Size
			frame.Parent = self.Gui

			table.insert(frames, frame)
			maid:GiveTask(frame)
		end
	end

	self.Gui.BackgroundTransparency = 1
	local alive = true
	maid:GiveTask(function()
		alive = false
		self.Done:Fire()
	end)

	for i=1, #frameList do
		local delayTime = squarePlaybackTime*(i/#frameList)
		delay(delayTime, function()
			if not alive then
				return
			end

			for _, frame in pairs(frameList[i]) do
				frame:TweenSize(UDim2.new(0, 0, 0, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, tweenTime, true)
			end
		end)
	end

	delay(playbackTime, function()
		maid:DoCleaning()
	end)
end

function ScreenCover:Destroy()
	self._maid:DoCleaning()
	self._maid = nil
end

return ScreenCover