local Y=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 w=game:GetService("\085\115\101\114\073\110\112\117\116\083\101\114\118\105\099\101")local T=game:GetService("\082\117\110\083\101\114\118\105\099\101")local t=game:GetService("\080\108\097\121\101\114\115")local M=game:GetService("\071\117\105\083\101\114\118\105\099\101")local p=Y("\083\110\097\099\107\098\097\114")local f=Y("\113\071\085\073")local y=setmetatable({},p)y.ClassName="\068\114\097\103\103\097\098\108\101\083\110\097\099\107\098\097\114"y.__index=y y.Vertical=true y.DefaultFadeOut="\070\097\100\101\079\117\116\068\111\119\110"y.Duration=3 y.AutoCloseDisabled=false function y.new(Y,w,T,M)local f=setmetatable(p.new(Y,w,M),y)f._visible=false f._draggingCoroutine=nil f._shouldDismiss=false f._showId=0 f._mouse=t.LocalPlayer:GetMouse()f._gcOnDismissal=T==nil and true or false f[f.DefaultFadeOut](f,true)return f end function y.Show(Y)if not Y._visible then Y._visible=true Y:FadeIn()local T=Y._showId+1 Y._showId=T Y._whileActiveMaid:GiveTask(Y.Gui.MouseButton1Down:Connect(function(w,t)if Y._showId==T then if not Y._draggingCoroutine then Y:StartTrack(w,t)end else warn("\091\068\114\097\103\103\105\110\103\066\101\103\105\110\069\118\101\110\116\093 - \115\101\108\102\046\095\115\104\111\119\073\100 ~\061 \076\111\099\097\108\083\104\111\119\073\100\044 \098\117\116 \101\118\101\110\116 \102\105\114\101\100")end end))Y._whileActiveMaid:GiveTask(w.InputBegan:Connect(function(w,t)if t then return end if Y._showId~=T then warn("\091\073\110\112\117\116\068\105\115\109\105\115\115\069\118\101\110\116\093 - \115\101\108\102\046\095\115\104\111\119\073\100 ~\061 \076\111\099\097\108\083\104\111\119\073\100\044 \098\117\116 \101\118\101\110\116 \102\105\114\101\100")return end if Y.AutoCloseDisabled then return end if f.MouseOver(Y._mouse,Y.Gui)then return end if Y.AbsolutePosition~=Y.Gui.AbsolutePosition then return end if w.UserInputType==Enum.UserInputType.Touch or w.UserInputType==Enum.UserInputType.MouseButton1 then Y:Dismiss()end end))delay(Y.Duration,function()if Y.Destroy and(Y._showId==T and Y._visible)then Y:Dismiss()end end)end end function y.StartTrack(M,Y,t)if M.Vertical then M._startDragPosition=t else M._startDragPosition=Y end M.DragOffset=0 local p p=coroutine.create(function()while M._draggingCoroutine==p do M:Track()T.Stepped:Wait()end end)M._draggingCoroutine=p M._whileActiveMaid.DraggingEnded=w.InputEnded:Connect(function(Y)if M._draggingCoroutine==p then if Y.UserInputType.Name=="\077\111\117\115\101\066\117\116\116\111\110\049"then M:EndTrack()end else warn("\091\068\114\097\103\103\097\098\108\101\083\110\097\099\107\098\097\114\093 - \073\110\112\117\116\069\110\100\101\100 \102\105\114\101\044 \098\117\116 \068\114\097\103\103\105\110\103\067\111\114\111\117\116\105\110\101 \119\097\115 \110\111\116 \116\104\101 \108\111\099\097\108\068\114\097\103\103\105\110\103\067\111\114\111\117\116\105\110\101")end end)M._whileActiveMaid.TouchDraggingEnded=w.TouchEnded:Connect(function(Y)if M._draggingCoroutine==p then M:EndTrack()else warn("\091\068\114\097\103\103\097\098\108\101\083\110\097\099\107\098\097\114\093 - \084\111\117\099\104\069\110\100\101\100 \102\105\114\101\044 \098\117\116 \068\114\097\103\103\105\110\103\067\111\114\111\117\116\105\110\101 \119\097\115 \110\111\116 \116\104\101 \108\111\099\097\108\068\114\097\103\103\105\110\103\067\111\114\111\117\116\105\110\101")end end)assert(coroutine.resume(M._draggingCoroutine))end function y.Track(Y)local w,T local t,p=M:GetGuiInset()if Y.Vertical then w=(Y._mouse.Y+t.Y)-Y._startDragPosition T=Y.Gui.AbsoluteSize.Y Y.Gui.Position=Y.Position+UDim2.new(0,0,0,w)else w=(Y._mouse.X+t.X)-Y._startDragPosition T=Y.Gui.AbsoluteSize.Y Y.Gui.Position=Y.Position+UDim2.new(0,w,0,0)end local f=math.abs(w)/T if f>1 then f=1 elseif f<0 then f=0 end Y:FadeOutTransparency(f)end function y.GetOffsetXY(Y)local w=Y.Gui.AbsolutePosition-Y.AbsolutePosition return w end function y.EndTrack(Y)Y._startDragPosition=nil Y._draggingCoroutine=nil Y._whileActiveMaid.DraggingEnded=nil Y._whileActiveMaid.TouchDraggingEnded=nil if Y._shouldDismiss then Y:Dismiss()else local w=Y:GetOffsetXY()local T=Y.Gui.AbsoluteSize if math.abs(w.X)>=T.X or math.abs(w.Y)>=T.Y then Y:Dismiss()else Y:FadeIn()end end end function y.Dismiss(Y)if Y._visible then if Y._draggingCoroutine then Y._shouldDismiss=true else Y._visible=false Y._shouldDismiss=nil Y._whileActiveMaid:DoCleaning()local w=Y:GetOffsetXY()if w.X>0 then Y:FadeOutRight()elseif w.X<0 then Y:FadeOutLeft()elseif w.Y>0 then Y:FadeOutUp()elseif w.Y<0 then Y:FadeOutDown()else Y[Y.DefaultFadeOut](Y)end if Y._gcOnDismissal then Y._gcOnDismissal=false delay(Y.FadeTime,function()Y:Destroy()end)end end else warn("\091\068\114\097\103\103\097\098\108\101\083\110\097\099\107\098\097\114\093 - \067\097\110\110\111\116 \100\105\115\109\105\115\115\044 \097\108\114\101\097\100\121 \104\105\100\100\101\110")end end function y.IsVisible(Y)return Y._visible end function y.Destroy(Y)Y.Gui:Destroy()Y.Gui=nil Y.TextLabel:Destroy()Y.TextLabel=nil Y._whileActiveMaid:DoCleaning()Y._whileActiveMaid=nil Y._visible=false Y._draggingCoroutine=nil setmetatable(Y,nil)end return y
--- Snackbar, but draggable
-- @classmod DraggableSnackbar

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

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Players  = game:GetService("Players")
local GuiService = game:GetService("GuiService")

local Snackbar = require("Snackbar")
local qGUI = require("qGUI")

local DraggableSnackbar = setmetatable({}, Snackbar)
DraggableSnackbar.ClassName = "DraggableSnackbar"
DraggableSnackbar.__index = DraggableSnackbar
DraggableSnackbar.Vertical = true
DraggableSnackbar.DefaultFadeOut = "FadeOutDown"
DraggableSnackbar.Duration = 3

-- By default the Snackbar will close automatically if the user types outside or presses the esc key.
DraggableSnackbar.AutoCloseDisabled = false

--- Note that this will not show until :Show() is called
-- @constructor
-- @param [GCOnDismissal] If true, will destroy itself and GC after being dismissed. Defaults to true
-- @param [Options] Table of optional values, adds call to actions, et cetera
function DraggableSnackbar.new(Parent, Text, GCOnDismissal, Options)
	local self = setmetatable(Snackbar.new(Parent, Text, Options), DraggableSnackbar)

	self._visible = false
	self._draggingCoroutine = nil
	self._shouldDismiss = false
	self._showId = 0

	self._mouse = Players.LocalPlayer:GetMouse()
	self._gcOnDismissal = GCOnDismissal == nil and true or false

	-- Set to transparency and faded out direction automatically
	self[self.DefaultFadeOut](self, true)

	return self
end

function DraggableSnackbar:Show()
	if not self._visible then
		self._visible = true
		self:FadeIn()
		local LocalShowId = self._showId + 1
		self._showId = LocalShowId

		-- Connect events
		self._whileActiveMaid:GiveTask(self.Gui.MouseButton1Down:Connect(function(X, Y)
			if self._showId == LocalShowId then
				if not self._draggingCoroutine then
					self:StartTrack(X, Y)
				end
			else
				warn("[DraggingBeginEvent] - self._showId ~= LocalShowId, but event fired")
			end
		end))

		self._whileActiveMaid:GiveTask(UserInputService.InputBegan:Connect(function(InputObject, GameProcessedEvent)
			if GameProcessedEvent then
				return
			end

			if self._showId ~= LocalShowId then
				warn("[InputDismissEvent] - self._showId ~= LocalShowId, but event fired")
				return
			end
			if self.AutoCloseDisabled then
				return
			end

			if qGUI.MouseOver(self._mouse, self.Gui) then
				return
			end

			if self.AbsolutePosition ~= self.Gui.AbsolutePosition then
				return -- Animating / dragging
			end

			if InputObject.UserInputType == Enum.UserInputType.Touch
				or InputObject.UserInputType == Enum.UserInputType.MouseButton1 then

				self:Dismiss()
			end
		end))

		--- Setup hide on dismissal
		delay(self.Duration, function()
			if self.Destroy and self._showId == LocalShowId and self._visible then
				self:Dismiss()
			end
		end)
	end
end

function DraggableSnackbar:StartTrack(X, Y)
	if self.Vertical then
		self._startDragPosition = Y
	else
		self._startDragPosition = X
	end
	self.DragOffset = 0

	local localDraggingCoroutine
	localDraggingCoroutine = coroutine.create(function()
		while self._draggingCoroutine == localDraggingCoroutine do
			self:Track()
			RunService.Stepped:Wait()
		end
	end)
	self._draggingCoroutine = localDraggingCoroutine

	self._whileActiveMaid.DraggingEnded = UserInputService.InputEnded:Connect(function(InputObject)
		if self._draggingCoroutine == localDraggingCoroutine then
			if InputObject.UserInputType.Name == "MouseButton1" then
				self:EndTrack()
			end
		else
			warn("[DraggableSnackbar] - InputEnded fire, but DraggingCoroutine was not the localDraggingCoroutine")
		end
	end)

	self._whileActiveMaid.TouchDraggingEnded = UserInputService.TouchEnded:Connect(function(InputObject)
		if self._draggingCoroutine == localDraggingCoroutine then
			self:EndTrack()
		else
			warn("[DraggableSnackbar] - TouchEnded fire, but DraggingCoroutine was not the localDraggingCoroutine")
		end
	end)

	assert(coroutine.resume(self._draggingCoroutine))
end

function DraggableSnackbar:Track()
	local DragOffset, DragLength
	local TopLeftInset, _ = GuiService:GetGuiInset()

	if self.Vertical then
		DragOffset = (self._mouse.Y + TopLeftInset.Y) - self._startDragPosition
		DragLength = self.Gui.AbsoluteSize.Y

		self.Gui.Position = self.Position + UDim2.new(0, 0, 0, DragOffset)
	else
		DragOffset = (self._mouse.X + TopLeftInset.X) - self._startDragPosition
		DragLength = self.Gui.AbsoluteSize.Y

		self.Gui.Position = self.Position + UDim2.new(0, DragOffset, 0, 0)
	end

	local PercentFaded = math.abs(DragOffset) / DragLength
	if PercentFaded > 1 then
		PercentFaded = 1
	elseif PercentFaded < 0 then
		PercentFaded = 0
	end

	self:FadeOutTransparency(PercentFaded)
end

function DraggableSnackbar:GetOffsetXY()
	local Offset = self.Gui.AbsolutePosition - self.AbsolutePosition
	return Offset
end

function DraggableSnackbar:EndTrack()
	self._startDragPosition = nil
	self._draggingCoroutine = nil

	-- Cleanup events
	self._whileActiveMaid.DraggingEnded = nil
	self._whileActiveMaid.TouchDraggingEnded = nil

	-- Dismissal if dragged out
	if self._shouldDismiss then
		self:Dismiss()
	else
		local OffsetXY = self:GetOffsetXY()
		local SizeXY = self.Gui.AbsoluteSize

		if math.abs(OffsetXY.X) >= SizeXY.X or math.abs(OffsetXY.Y) >= SizeXY.Y then
			self:Dismiss()
		else
			self:FadeIn()
		end
	end
end

function DraggableSnackbar:Dismiss()
	if self._visible then
		if (self._draggingCoroutine) then
			self._shouldDismiss = true
		else
			self._visible = false
			self._shouldDismiss = nil
			self._whileActiveMaid:DoCleaning()

			local OffsetXY = self:GetOffsetXY()
			-- Determine what direction to fade out...
			if OffsetXY.X > 0 then
				self:FadeOutRight()
			elseif OffsetXY.X < 0 then
				self:FadeOutLeft()
			elseif OffsetXY.Y > 0 then
				self:FadeOutUp()
			elseif OffsetXY.Y < 0 then
				self:FadeOutDown()
			else
				self[self.DefaultFadeOut](self)
			end

			-- GC stuff
			if self._gcOnDismissal then
				self._gcOnDismissal = false -- Make sure this is only called once...
				delay(self.FadeTime, function()
					self:Destroy()
				end)
			end
		end
	else
		warn("[DraggableSnackbar] - Cannot dismiss, already hidden")
	end
end

function DraggableSnackbar:IsVisible()
	return self._visible
end

function DraggableSnackbar:Destroy()
	self.Gui:Destroy()
	self.Gui = nil

	self.TextLabel:Destroy()
	self.TextLabel = nil

	self._whileActiveMaid:DoCleaning()
	self._whileActiveMaid = nil

	self._visible = false
	self._draggingCoroutine = nil

	setmetatable(self, nil)
end

return DraggableSnackbar
