local w={}local u=script.Parent.Parent.Parent local T=game:GetService("\067\104\097\116")local S=u:WaitForChild("\067\108\105\101\110\116\067\104\097\116\077\111\100\117\108\101\115")local Z=script.Parent local g=require(Z:WaitForChild("\067\104\097\110\110\101\108\115\084\097\098"))local o=require(Z:WaitForChild("\077\101\115\115\097\103\101\083\101\110\100\101\114"))local e=require(S:WaitForChild("\067\104\097\116\083\101\116\116\105\110\103\115"))local J=require(Z:WaitForChild("\067\117\114\118\101\085\116\105\108"))local d={}d.__index=d function d.CreateGuiObjects(u,w)local T=Instance.new("\070\114\097\109\101")T.Selectable=false T.Size=UDim2.new(1,0,1,0)T.BackgroundTransparency=1 T.Parent=w local S=Instance.new("\070\114\097\109\101")S.Selectable=false S.Name="\083\099\114\111\108\108\105\110\103\066\097\115\101"S.BackgroundTransparency=1 S.ClipsDescendants=true S.Size=UDim2.new(1,0,1,0)S.Position=UDim2.new(0,0,0,0)S.Parent=T local Z=Instance.new("\070\114\097\109\101")Z.Selectable=false Z.Name="\083\099\114\111\108\108\101\114\083\105\122\101\114"Z.BackgroundTransparency=1 Z.Size=UDim2.new(1,0,1,0)Z.Position=UDim2.new(0,0,0,0)Z.Parent=S local g=Instance.new("\070\114\097\109\101")g.Selectable=false g.Name="\083\099\114\111\108\108\101\114\070\114\097\109\101"g.BackgroundTransparency=1 g.Size=UDim2.new(1,0,1,0)g.Position=UDim2.new(0,0,0,0)g.Parent=Z local J=Instance.new("\070\114\097\109\101")J.Selectable=false J.Size=UDim2.new(1,0,1,0)J.Position=UDim2.new(0,0,0,0)J.ClipsDescendants=true J.BackgroundTransparency=1 J.Parent=T local d=Instance.new("\070\114\097\109\101")d.Selectable=false d.Name="\076\101\097\118\101\067\111\110\102\105\114\109\097\116\105\111\110\070\114\097\109\101"d.Size=UDim2.new(1,0,1,0)d.Position=UDim2.new(0,0,1,0)d.BackgroundTransparency=.6 d.BorderSizePixel=0 d.BackgroundColor3=Color3.new(0,0,0)d.Parent=J local C=Instance.new("\084\101\120\116\066\117\116\116\111\110")C.Selectable=false C.Size=UDim2.new(1,0,1,0)C.BackgroundTransparency=1 C.Text=""C.Parent=d local s=Instance.new("\084\101\120\116\066\117\116\116\111\110")s.Selectable=false s.Size=UDim2.new(.25,0,1,0)s.BackgroundTransparency=1 s.Font=e.DefaultFont s.TextSize=18 s.TextStrokeTransparency=.75 s.Position=UDim2.new(0,0,0,0)s.TextColor3=Color3.new(0,1,0)s.Text="\067\111\110\102\105\114\109"s.Parent=d local K=s:Clone()K.Parent=d K.Position=UDim2.new(.75,0,0,0)K.TextColor3=Color3.new(1,0,0)K.Text="\067\097\110\099\101\108"local N=Instance.new("\084\101\120\116\076\097\098\101\108")N.Selectable=false N.Size=UDim2.new(.5,0,1,0)N.Position=UDim2.new(.25,0,0,0)N.BackgroundTransparency=1 N.TextColor3=Color3.new(1,1,1)N.TextStrokeTransparency=.75 N.Text="\076\101\097\118\101 \099\104\097\110\110\101\108 \060\088\088\062\063"N.Font=e.DefaultFont N.TextSize=18 N.Parent=d local D=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")D.Name="\076\101\097\118\101\084\097\114\103\101\116"D.Parent=d local R=d.Position s.MouseButton1Click:connect(function()o:SendMessage(string.format("\047\108\101\097\118\101 \037\115",D.Value),nil)d:TweenPosition(R,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.2,true)end)K.MouseButton1Click:connect(function()d:TweenPosition(R,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.2,true)end)local W=.7 local m=(1-W)/2 local i="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\117\105\047\067\104\097\116\047\084\097\098\065\114\114\111\119\066\097\099\107\103\114\111\117\110\100\046\112\110\103"local j="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\117\105\047\067\104\097\116\047\084\097\098\065\114\114\111\119\046\112\110\103"i="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\055\049\054\051\048\049\057\057"j="\114\098\120\097\115\115\101\116\105\100\058\047\047\052\055\049\054\051\048\049\049\050"local v=Instance.new("\073\109\097\103\101\066\117\116\116\111\110",T)v.Selectable=e.GamepadNavigationEnabled v.Name="\080\097\103\101\076\101\102\116\066\117\116\116\111\110"v.SizeConstraint=Enum.SizeConstraint.RelativeYY v.Size=UDim2.new(W,0,W,0)v.BackgroundTransparency=1 v.Position=UDim2.new(0,4,m,0)v.Visible=false v.Image=i local r=Instance.new("\073\109\097\103\101\076\097\098\101\108",v)r.Name="\065\114\114\111\119\076\097\098\101\108"r.BackgroundTransparency=1 r.Size=UDim2.new(.4,0,.4,0)r.Image=j local X=Instance.new("\070\114\097\109\101",T)X.Selectable=false X.BackgroundTransparency=1 X.Name="\080\111\115\105\116\105\111\110\097\108\072\101\108\112\101\114"X.Size=v.Size X.SizeConstraint=v.SizeConstraint X.Position=UDim2.new(1,0,m,0)local H=v:Clone()H.Parent=X H.Name="\080\097\103\101\082\105\103\104\116\066\117\116\116\111\110"H.Size=UDim2.new(1,0,1,0)H.SizeConstraint=Enum.SizeConstraint.RelativeXY H.Position=UDim2.new(-1,-4,0,0)local n=UDim2.new(.05,0,0,0)H.ArrowLabel.Position=UDim2.new(.3,0,.3,0)+n v.ArrowLabel.Position=UDim2.new(.3,0,.3,0)-n v.ArrowLabel.Rotation=180 u.GuiObject=T u.GuiObjects.BaseFrame=T u.GuiObjects.ScrollerSizer=Z u.GuiObjects.ScrollerFrame=g u.GuiObjects.PageLeftButton=v u.GuiObjects.PageRightButton=H u.GuiObjects.LeaveConfirmationFrame=d u.GuiObjects.LeaveConfirmationNotice=N u.GuiObjects.PageLeftButtonArrow=v.ArrowLabel u.GuiObjects.PageRightButtonArrow=H.ArrowLabel u:AnimGuiObjects()v.MouseButton1Click:connect(function()u:ScrollChannelsFrame(-1)end)H.MouseButton1Click:connect(function()u:ScrollChannelsFrame(1)end)u:ScrollChannelsFrame(0)end function d.UpdateMessagePostedInChannel(u,w)local T=u:GetChannelTab(w)if T then T:UpdateMessagePostedInChannel()else warn("\067\104\097\110\110\101\108\115\084\097\098 \'"..(w.."\' \100\111\101\115 \110\111\116 \101\120\105\115\116\033"))end end function d.AddChannelTab(u,w)if u:GetChannelTab(w)then error("\067\104\097\110\110\101\108 \116\097\098 \'"..(w.."\'\097\108\114\101\097\100\121 \101\120\105\115\116\115\033"))end local T=g.new(w)T.GuiObject.Parent=u.GuiObjects.ScrollerFrame u.ChannelTabs[w:lower()]=T u.NumTabs=u.NumTabs+1 u:OrganizeChannelTabs()if e.RightClickToLeaveChannelEnabled then T.NameTag.MouseButton2Click:connect(function()u.LeaveConfirmationNotice.Text=string.format("\076\101\097\118\101 \099\104\097\110\110\101\108 \037\115\063",T.ChannelName)u.LeaveConfirmationFrame.LeaveTarget.Value=T.ChannelName u.LeaveConfirmationFrame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.In,Enum.EasingStyle.Quad,.2,true)end)end return T end function d.RemoveChannelTab(u,w)if not u:GetChannelTab(w)then error("\067\104\097\110\110\101\108 \116\097\098 \'"..(w.."\'\100\111\101\115 \110\111\116 \101\120\105\115\116\033"))end local T=w:lower()u.ChannelTabs[T]:Destroy()u.ChannelTabs[T]=nil u.NumTabs=u.NumTabs-1 u:OrganizeChannelTabs()end function d.GetChannelTab(u,w)return u.ChannelTabs[w:lower()]end function d.OrganizeChannelTabs(w)local u={}table.insert(u,w:GetChannelTab(e.GeneralChannelName))table.insert(u,w:GetChannelTab("\083\121\115\116\101\109"))for w,T in pairs(w.ChannelTabs)do if T.ChannelName~=e.GeneralChannelName and T.ChannelName~="\083\121\115\116\101\109"then table.insert(u,T)end end for w,u in pairs(u)do u.GuiObject.Position=UDim2.new(w-1,0,0,0)end w.GuiObjects.ScrollerSizer.Size=UDim2.new(1/math.max(1,math.min(e.ChannelsBarFullTabSize,w.NumTabs)),0,1,0)w:ScrollChannelsFrame(0)end function d.ResizeChannelTabText(u,w)for u,T in pairs(u.ChannelTabs)do T:SetTextSize(w)end end function d.ScrollChannelsFrame(u,w)if u.ScrollChannelsFrameLock then return end u.ScrollChannelsFrameLock=true local T=e.ChannelsBarFullTabSize local S=u.CurPageNum+w if S<0 then S=0 elseif S>0 and S+T>u.NumTabs then S=u.NumTabs-T end u.CurPageNum=S local Z=.15 local g=UDim2.new(-u.CurPageNum,0,0,0)u.GuiObjects.PageLeftButton.Visible=u.CurPageNum>0 u.GuiObjects.PageRightButton.Visible=u.CurPageNum+T<u.NumTabs if w==0 then u.ScrollChannelsFrameLock=false return end local function o()u.ScrollChannelsFrameLock=false end u:WaitUntilParentedCorrectly()u.GuiObjects.ScrollerFrame:TweenPosition(g,Enum.EasingDirection.InOut,Enum.EasingStyle.Quad,Z,true,o)end function d.FadeOutBackground(u,w)for u,T in pairs(u.ChannelTabs)do T:FadeOutBackground(w)end u.AnimParams.Background_TargetTransparency=1 u.AnimParams.Background_NormalizedExptValue=J:NormalizedDefaultExptValueInSeconds(w)end function d.FadeInBackground(u,w)for u,T in pairs(u.ChannelTabs)do T:FadeInBackground(w)end u.AnimParams.Background_TargetTransparency=.6 u.AnimParams.Background_NormalizedExptValue=J:NormalizedDefaultExptValueInSeconds(w)end function d.FadeOutText(u,w)for u,T in pairs(u.ChannelTabs)do T:FadeOutText(w)end end function d.FadeInText(u,w)for u,T in pairs(u.ChannelTabs)do T:FadeInText(w)end end function d.AnimGuiObjects(w)w.GuiObjects.PageLeftButton.ImageTransparency=w.AnimParams.Background_CurrentTransparency w.GuiObjects.PageRightButton.ImageTransparency=w.AnimParams.Background_CurrentTransparency w.GuiObjects.PageLeftButtonArrow.ImageTransparency=w.AnimParams.Background_CurrentTransparency w.GuiObjects.PageRightButtonArrow.ImageTransparency=w.AnimParams.Background_CurrentTransparency end function d.InitializeAnimParams(w)w.AnimParams.Background_TargetTransparency=.6 w.AnimParams.Background_CurrentTransparency=.6 w.AnimParams.Background_NormalizedExptValue=J:NormalizedDefaultExptValueInSeconds(0)end function d.Update(u,w)for u,T in pairs(u.ChannelTabs)do T:Update(w)end u.AnimParams.Background_CurrentTransparency=J:Expt(u.AnimParams.Background_CurrentTransparency,u.AnimParams.Background_TargetTransparency,u.AnimParams.Background_NormalizedExptValue,w)u:AnimGuiObjects()end function d.WaitUntilParentedCorrectly(w)while not w.GuiObject:IsDescendantOf((game:GetService("\080\108\097\121\101\114\115")).LocalPlayer)do w.GuiObject.AncestryChanged:wait()end end function w.new()local w=setmetatable({},d)w.GuiObject=nil w.GuiObjects={}w.ChannelTabs={}w.NumTabs=0 w.CurPageNum=0 w.ScrollChannelsFrameLock=false w.AnimParams={}w:InitializeAnimParams()e.SettingsChanged:connect(function(u,T)if u=="\067\104\097\116\067\104\097\110\110\101\108\115\084\097\098\084\101\120\116\083\105\122\101"then w:ResizeChannelTabText(T)end end)return w end return w
--!nonstrict
--	// FileName: ChannelsBar.lua
--	// Written by: Xsitsu
--	// Description: Manages creating, destroying, and displaying ChannelTabs.

local module = {}

--////////////////////////////// Include
--//////////////////////////////////////
local chatFolder = script.Parent.Parent.Parent

local Chat = game:GetService("Chat")
local clientChatModules = chatFolder:WaitForChild("ClientChatModules")
local modulesFolder = script.Parent
local moduleChannelsTab = require(modulesFolder:WaitForChild("ChannelsTab"))
local MessageSender = require(modulesFolder:WaitForChild("MessageSender"))
local ChatSettings = require(clientChatModules:WaitForChild("ChatSettings"))
local CurveUtil = require(modulesFolder:WaitForChild("CurveUtil"))

--////////////////////////////// Methods
--//////////////////////////////////////
local methods = {}
methods.__index = methods

function methods:CreateGuiObjects(targetParent)
	local BaseFrame = Instance.new("Frame")
	BaseFrame.Selectable = false
	BaseFrame.Size = UDim2.new(1, 0, 1, 0)
	BaseFrame.BackgroundTransparency = 1
	BaseFrame.Parent = targetParent

	local ScrollingBase = Instance.new("Frame")
	ScrollingBase.Selectable = false
	ScrollingBase.Name = "ScrollingBase"
	ScrollingBase.BackgroundTransparency = 1
	ScrollingBase.ClipsDescendants = true
	ScrollingBase.Size = UDim2.new(1, 0, 1, 0)
	ScrollingBase.Position = UDim2.new(0, 0, 0, 0)
	ScrollingBase.Parent = BaseFrame

	local ScrollerSizer = Instance.new("Frame")
	ScrollerSizer.Selectable = false
	ScrollerSizer.Name = "ScrollerSizer"
	ScrollerSizer.BackgroundTransparency = 1
	ScrollerSizer.Size = UDim2.new(1, 0, 1, 0)
	ScrollerSizer.Position = UDim2.new(0, 0, 0, 0)
	ScrollerSizer.Parent = ScrollingBase

	local ScrollerFrame = Instance.new("Frame")
	ScrollerFrame.Selectable = false
	ScrollerFrame.Name = "ScrollerFrame"
	ScrollerFrame.BackgroundTransparency = 1
	ScrollerFrame.Size = UDim2.new(1, 0, 1, 0)
	ScrollerFrame.Position = UDim2.new(0, 0, 0, 0)
	ScrollerFrame.Parent = ScrollerSizer

	local LeaveConfirmationFrameBase = Instance.new("Frame")
	LeaveConfirmationFrameBase.Selectable = false
	LeaveConfirmationFrameBase.Size = UDim2.new(1, 0, 1, 0)
	LeaveConfirmationFrameBase.Position = UDim2.new(0, 0, 0, 0)
	LeaveConfirmationFrameBase.ClipsDescendants = true
	LeaveConfirmationFrameBase.BackgroundTransparency = 1
	LeaveConfirmationFrameBase.Parent = BaseFrame

	local LeaveConfirmationFrame = Instance.new("Frame")
	LeaveConfirmationFrame.Selectable = false
	LeaveConfirmationFrame.Name = "LeaveConfirmationFrame"
	LeaveConfirmationFrame.Size = UDim2.new(1, 0, 1, 0)
	LeaveConfirmationFrame.Position = UDim2.new(0, 0, 1, 0)
	LeaveConfirmationFrame.BackgroundTransparency = 0.6
	LeaveConfirmationFrame.BorderSizePixel = 0
	LeaveConfirmationFrame.BackgroundColor3 = Color3.new(0, 0, 0)
	LeaveConfirmationFrame.Parent = LeaveConfirmationFrameBase

	local InputBlocker = Instance.new("TextButton")
	InputBlocker.Selectable = false
	InputBlocker.Size = UDim2.new(1, 0, 1, 0)
	InputBlocker.BackgroundTransparency = 1
	InputBlocker.Text = ""
	InputBlocker.Parent = LeaveConfirmationFrame

	local LeaveConfirmationButtonYes = Instance.new("TextButton")
	LeaveConfirmationButtonYes.Selectable = false
	LeaveConfirmationButtonYes.Size = UDim2.new(0.25, 0, 1, 0)
	LeaveConfirmationButtonYes.BackgroundTransparency = 1
	LeaveConfirmationButtonYes.Font = ChatSettings.DefaultFont
	LeaveConfirmationButtonYes.TextSize = 18
	LeaveConfirmationButtonYes.TextStrokeTransparency = 0.75
	LeaveConfirmationButtonYes.Position = UDim2.new(0, 0, 0, 0)
	LeaveConfirmationButtonYes.TextColor3 = Color3.new(0, 1, 0)
	LeaveConfirmationButtonYes.Text = "Confirm"
	LeaveConfirmationButtonYes.Parent = LeaveConfirmationFrame

	local LeaveConfirmationButtonNo = LeaveConfirmationButtonYes:Clone()
	LeaveConfirmationButtonNo.Parent = LeaveConfirmationFrame
	LeaveConfirmationButtonNo.Position = UDim2.new(0.75, 0, 0, 0)
	LeaveConfirmationButtonNo.TextColor3 = Color3.new(1, 0, 0)
	LeaveConfirmationButtonNo.Text = "Cancel"

	local LeaveConfirmationNotice = Instance.new("TextLabel")
	LeaveConfirmationNotice.Selectable = false
	LeaveConfirmationNotice.Size = UDim2.new(0.5, 0, 1, 0)
	LeaveConfirmationNotice.Position = UDim2.new(0.25, 0, 0, 0)
	LeaveConfirmationNotice.BackgroundTransparency = 1
	LeaveConfirmationNotice.TextColor3 = Color3.new(1, 1, 1)
	LeaveConfirmationNotice.TextStrokeTransparency = 0.75
	LeaveConfirmationNotice.Text = "Leave channel <XX>?"
	LeaveConfirmationNotice.Font = ChatSettings.DefaultFont
	LeaveConfirmationNotice.TextSize = 18
	LeaveConfirmationNotice.Parent = LeaveConfirmationFrame

	local LeaveTarget = Instance.new("StringValue")
	LeaveTarget.Name = "LeaveTarget"
	LeaveTarget.Parent = LeaveConfirmationFrame

	local outPos = LeaveConfirmationFrame.Position
	LeaveConfirmationButtonYes.MouseButton1Click:connect(function()
		MessageSender:SendMessage(string.format("/leave %s", LeaveTarget.Value), nil)
		LeaveConfirmationFrame:TweenPosition(outPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.2, true)
	end)
	LeaveConfirmationButtonNo.MouseButton1Click:connect(function()
		LeaveConfirmationFrame:TweenPosition(outPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.2, true)
	end)

	local scale = 0.7
	local scaleOther = (1 - scale) / 2
	local pageButtonImage = "rbxasset://textures/ui/Chat/TabArrowBackground.png"
	local pageButtonArrowImage = "rbxasset://textures/ui/Chat/TabArrow.png"

	--// ToDo: Remove these lines when the assets are put into trunk.
	--// These grab unchanging versions hosted on the site, and not from the content folder.
	pageButtonImage = "rbxassetid://471630199"
	pageButtonArrowImage = "rbxassetid://471630112"

	local PageLeftButton = Instance.new("ImageButton", BaseFrame)
	PageLeftButton.Selectable = ChatSettings.GamepadNavigationEnabled
	PageLeftButton.Name = "PageLeftButton"
	PageLeftButton.SizeConstraint = Enum.SizeConstraint.RelativeYY
	PageLeftButton.Size = UDim2.new(scale, 0, scale, 0)
	PageLeftButton.BackgroundTransparency = 1
	PageLeftButton.Position = UDim2.new(0, 4, scaleOther, 0)
	PageLeftButton.Visible = false
	PageLeftButton.Image = pageButtonImage
	local ArrowLabel = Instance.new("ImageLabel", PageLeftButton)
	ArrowLabel.Name = "ArrowLabel"
	ArrowLabel.BackgroundTransparency = 1
	ArrowLabel.Size = UDim2.new(0.4, 0, 0.4, 0)
	ArrowLabel.Image = pageButtonArrowImage

	local PageRightButtonPositionalHelper = Instance.new("Frame", BaseFrame)
	PageRightButtonPositionalHelper.Selectable = false
	PageRightButtonPositionalHelper.BackgroundTransparency = 1
	PageRightButtonPositionalHelper.Name = "PositionalHelper"
	PageRightButtonPositionalHelper.Size = PageLeftButton.Size
	PageRightButtonPositionalHelper.SizeConstraint = PageLeftButton.SizeConstraint
	PageRightButtonPositionalHelper.Position = UDim2.new(1, 0, scaleOther, 0)

	local PageRightButton = PageLeftButton:Clone()
	PageRightButton.Parent = PageRightButtonPositionalHelper
	PageRightButton.Name = "PageRightButton"
	PageRightButton.Size = UDim2.new(1, 0, 1, 0)
	PageRightButton.SizeConstraint = Enum.SizeConstraint.RelativeXY
	PageRightButton.Position = UDim2.new(-1, -4, 0, 0)

	local positionOffset = UDim2.new(0.05, 0, 0, 0)

	PageRightButton.ArrowLabel.Position = UDim2.new(0.3, 0, 0.3, 0) + positionOffset
	PageLeftButton.ArrowLabel.Position = UDim2.new(0.3, 0, 0.3, 0) - positionOffset
	PageLeftButton.ArrowLabel.Rotation = 180

	self.GuiObject = BaseFrame

	self.GuiObjects.BaseFrame = BaseFrame
	self.GuiObjects.ScrollerSizer = ScrollerSizer
	self.GuiObjects.ScrollerFrame = ScrollerFrame
	self.GuiObjects.PageLeftButton = PageLeftButton
	self.GuiObjects.PageRightButton = PageRightButton
	self.GuiObjects.LeaveConfirmationFrame = LeaveConfirmationFrame
	self.GuiObjects.LeaveConfirmationNotice = LeaveConfirmationNotice

	self.GuiObjects.PageLeftButtonArrow = PageLeftButton.ArrowLabel
	self.GuiObjects.PageRightButtonArrow = PageRightButton.ArrowLabel
	self:AnimGuiObjects()

	PageLeftButton.MouseButton1Click:connect(function()
		self:ScrollChannelsFrame(-1)
	end)
	PageRightButton.MouseButton1Click:connect(function()
		self:ScrollChannelsFrame(1)
	end)

	self:ScrollChannelsFrame(0)
end

function methods:UpdateMessagePostedInChannel(channelName)
	local tab = self:GetChannelTab(channelName)
	if tab then
		tab:UpdateMessagePostedInChannel()
	else
		warn("ChannelsTab '" .. channelName .. "' does not exist!")
	end
end

function methods:AddChannelTab(channelName)
	if self:GetChannelTab(channelName) then
		error("Channel tab '" .. channelName .. "'already exists!")
	end

	local tab = moduleChannelsTab.new(channelName)
	tab.GuiObject.Parent = self.GuiObjects.ScrollerFrame
	self.ChannelTabs[channelName:lower()] = tab

	self.NumTabs = self.NumTabs + 1
	self:OrganizeChannelTabs()

	if ChatSettings.RightClickToLeaveChannelEnabled then
		tab.NameTag.MouseButton2Click:connect(function()
			self.LeaveConfirmationNotice.Text = string.format("Leave channel %s?", tab.ChannelName)
			self.LeaveConfirmationFrame.LeaveTarget.Value = tab.ChannelName
			self.LeaveConfirmationFrame:TweenPosition(
				UDim2.new(0, 0, 0, 0),
				Enum.EasingDirection.In,
				Enum.EasingStyle.Quad,
				0.2,
				true
			)
		end)
	end

	return tab
end

function methods:RemoveChannelTab(channelName)
	if not self:GetChannelTab(channelName) then
		error("Channel tab '" .. channelName .. "'does not exist!")
	end

	local indexName = channelName:lower()
	self.ChannelTabs[indexName]:Destroy()
	self.ChannelTabs[indexName] = nil

	self.NumTabs = self.NumTabs - 1
	self:OrganizeChannelTabs()
end

function methods:GetChannelTab(channelName)
	return self.ChannelTabs[channelName:lower()]
end

function methods:OrganizeChannelTabs()
	local order = {}

	table.insert(order, self:GetChannelTab(ChatSettings.GeneralChannelName))
	table.insert(order, self:GetChannelTab("System"))

	for tabIndexName, tab in pairs(self.ChannelTabs) do
		if tab.ChannelName ~= ChatSettings.GeneralChannelName and tab.ChannelName ~= "System" then
			table.insert(order, tab)
		end
	end

	for index, tab in pairs(order) do
		tab.GuiObject.Position = UDim2.new(index - 1, 0, 0, 0)
	end

	--// Dynamic tab resizing
	self.GuiObjects.ScrollerSizer.Size =
		UDim2.new(1 / math.max(1, math.min(ChatSettings.ChannelsBarFullTabSize, self.NumTabs)), 0, 1, 0)

	self:ScrollChannelsFrame(0)
end

function methods:ResizeChannelTabText(textSize)
	for i, tab in pairs(self.ChannelTabs) do
		tab:SetTextSize(textSize)
	end
end

function methods:ScrollChannelsFrame(dir)
	if self.ScrollChannelsFrameLock then
		return
	end
	self.ScrollChannelsFrameLock = true

	local tabNumber = ChatSettings.ChannelsBarFullTabSize

	local newPageNum = self.CurPageNum + dir
	if newPageNum < 0 then
		newPageNum = 0
	elseif newPageNum > 0 and newPageNum + tabNumber > self.NumTabs then
		newPageNum = self.NumTabs - tabNumber
	end

	self.CurPageNum = newPageNum

	local tweenTime = 0.15
	local endPos = UDim2.new(-self.CurPageNum, 0, 0, 0)

	self.GuiObjects.PageLeftButton.Visible = (self.CurPageNum > 0)
	self.GuiObjects.PageRightButton.Visible = (self.CurPageNum + tabNumber < self.NumTabs)

	if dir == 0 then
		self.ScrollChannelsFrameLock = false
		return
	end

	local function UnlockFunc()
		self.ScrollChannelsFrameLock = false
	end

	self:WaitUntilParentedCorrectly()

	self.GuiObjects.ScrollerFrame:TweenPosition(
		endPos,
		Enum.EasingDirection.InOut,
		Enum.EasingStyle.Quad,
		tweenTime,
		true,
		UnlockFunc
	)
end

function methods:FadeOutBackground(duration)
	for channelName, channelObj in pairs(self.ChannelTabs) do
		channelObj:FadeOutBackground(duration)
	end

	self.AnimParams.Background_TargetTransparency = 1
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end

function methods:FadeInBackground(duration)
	for channelName, channelObj in pairs(self.ChannelTabs) do
		channelObj:FadeInBackground(duration)
	end

	self.AnimParams.Background_TargetTransparency = 0.6
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(duration)
end

function methods:FadeOutText(duration)
	for channelName, channelObj in pairs(self.ChannelTabs) do
		channelObj:FadeOutText(duration)
	end
end

function methods:FadeInText(duration)
	for channelName, channelObj in pairs(self.ChannelTabs) do
		channelObj:FadeInText(duration)
	end
end

function methods:AnimGuiObjects()
	self.GuiObjects.PageLeftButton.ImageTransparency = self.AnimParams.Background_CurrentTransparency
	self.GuiObjects.PageRightButton.ImageTransparency = self.AnimParams.Background_CurrentTransparency
	self.GuiObjects.PageLeftButtonArrow.ImageTransparency = self.AnimParams.Background_CurrentTransparency
	self.GuiObjects.PageRightButtonArrow.ImageTransparency = self.AnimParams.Background_CurrentTransparency
end

function methods:InitializeAnimParams()
	self.AnimParams.Background_TargetTransparency = 0.6
	self.AnimParams.Background_CurrentTransparency = 0.6
	self.AnimParams.Background_NormalizedExptValue = CurveUtil:NormalizedDefaultExptValueInSeconds(0)
end

function methods:Update(dtScale)
	for channelName, channelObj in pairs(self.ChannelTabs) do
		channelObj:Update(dtScale)
	end

	self.AnimParams.Background_CurrentTransparency = CurveUtil:Expt(
		self.AnimParams.Background_CurrentTransparency,
		self.AnimParams.Background_TargetTransparency,
		self.AnimParams.Background_NormalizedExptValue,
		dtScale
	)

	self:AnimGuiObjects()
end

--// ToDo: Move to common modules
function methods:WaitUntilParentedCorrectly()
	while not self.GuiObject:IsDescendantOf(game:GetService("Players").LocalPlayer) do
		self.GuiObject.AncestryChanged:wait()
	end
end

--///////////////////////// Constructors
--//////////////////////////////////////

function module.new()
	local obj = setmetatable({}, methods)

	obj.GuiObject = nil
	obj.GuiObjects = {}

	obj.ChannelTabs = {}
	obj.NumTabs = 0
	obj.CurPageNum = 0

	obj.ScrollChannelsFrameLock = false

	obj.AnimParams = {}

	obj:InitializeAnimParams()

	ChatSettings.SettingsChanged:connect(function(setting, value)
		if setting == "ChatChannelsTabTextSize" then
			obj:ResizeChannelTabText(value)
		end
	end)

	return obj
end

return module
