function Icon.set(l,N,k,z,L)local K=l._settingsDictionary[N]assert(K~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(N))if type(z)=="\115\116\114\105\110\103"then z=z:lower()end local w=l:get(N,z)local s=K.type if s=="\116\111\103\103\108\101\097\098\108\101"then local N={}if z=="\100\101\115\101\108\101\099\116\101\100"or z=="\115\101\108\101\099\116\101\100"then table.insert(N,z)else table.insert(N,"\100\101\115\101\108\101\099\116\101\100")table.insert(N,"\115\101\108\101\099\116\101\100")z=nil end for N,z in pairs(N)do K.values[z]=k if L~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then K.additionalValues["\112\114\101\118\105\111\117\115\095"..z]=w end if type(L)=="\115\116\114\105\110\103"then K.additionalValues[L..("\095"..z)]=w end end else K.value=k if type(L)=="\115\116\114\105\110\103"then if L~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then K.additionalValues.previous=w end K.additionalValues[L]=w end end if w==k then return l,"\086\097\108\117\101 \119\097\115 \097\108\114\101\097\100\121 \115\101\116"end local M=l:getToggleState()if not l._updateAfterSettingAll and(K.instanceNames and(M==z or z==nil))then l:_update(N,M,true)end if K.callMethods then for N,L in pairs(K.callMethods)do L(l,k,z)end end if K.callSignals then for N,k in pairs(K.callSignals)do k:Fire()end end return l end function Icon.get(L,N,k,z)local l=L._settingsDictionary[N]assert(l~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(N))local K=l.type if K=="\116\111\103\103\108\101\097\098\108\101"then k=k or L:getToggleState()local N=type(z)=="\115\116\114\105\110\103"and l.additionalValues[z..("\095"..k)]return l.values[k],N end local w=type(z)=="\115\116\114\105\110\103"and l.additionalValues[z]return l.value,w end function Icon.getToggleState(k,N)N=N or k.isSelected return N and"\115\101\108\101\099\116\101\100"or"\100\101\115\101\108\101\099\116\101\100"end function Icon._update(L,N,k,z)local l=L._settingsDictionary[N]assert(l~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(N))k=k or L:getToggleState()local K=l.value or l.values and l.values[k]if K==nil then return end local w=z and TweenInfo.new(0)or L._settings.action.toggleTransitionInfo.value local s=l.propertyName local M={string=true,NumberSequence=true;Text=true;EnumItem=true;ColorSequence=true}local O=L._uniqueSettingsDictionary[N]for k,z in pairs(l.instanceNames)do local l=L.instances[z]local j=typeof(l[s])local X=M[j]if O then O(N,l,s,K)elseif X then l[s]=K else(tweenService:Create(l,w,{[s]=K})):Play()end if N=="\105\099\111\110\083\105\122\101"and l[s]~=K then L.updated:Fire()end end end function Icon._updateAll(z,N,k)for L,l in pairs(z._settingsDictionary)do if l.instanceNames then z:_update(L,N,k)end end end function Icon._updateStateOverlay(z,N,k)local L=z.instances.iconOverlay L.BackgroundTransparency=N or 1 L.BackgroundColor3=k or Color3.new(1,1,1)end function Icon.setTheme(z,N,k)z._updateAfterSettingAll=k for N,k in pairs(N)do if N=="\116\111\103\103\108\101\097\098\108\101"then for N,k in pairs(k.deselected)do z:set(N,k,"\098\111\116\104")end for N,k in pairs(k.selected)do z:set(N,k,"\115\101\108\101\099\116\101\100")end else for N,k in pairs(k)do z:set(N,k)end end end z._updateAfterSettingAll=nil if k then z:_updateAll()end return z end function Icon.setEnabled(k,N)k.enabled=N k.instances.iconContainer.Visible=N k.updated:Fire()return k end function Icon.setName(k,N)k.name=N k.instances.iconContainer.Name=N return k end function Icon._playClickSound(N)local k=N.instances.clickSound if k.SoundId~=nil and(#k.SoundId>0 and k.Volume>0)then local N=k:Clone()N.Parent=k.Parent N:Play()debris:AddItem(N,k.TimeLength)end end function Icon.select(k,N)if k.locked then return k end k.isSelected=true k:_setToggleItemsVisible(true,N)k:_updateNotice()k:_updateAll()k:_playClickSound()if#k.dropdownIcons>0 or#k.menuIcons>0 then IconController:_updateSelectionGroup()end k.selected:Fire()k.toggled:Fire(k.isSelected)return k end function Icon.deselect(k,N)if k.locked then return k end k.isSelected=false k:_setToggleItemsVisible(false,N)k:_updateNotice()k:_updateAll()k:_playClickSound()if#k.dropdownIcons>0 or#k.menuIcons>0 then IconController:_updateSelectionGroup()end k.deselected:Fire()k.toggled:Fire(k.isSelected)return k end function Icon.notify(z,N,k)(coroutine.wrap(function()if not N then N=z.deselected end if z._parentIcon then z._parentIcon:notify(N)end local L=Signal.new()local l=z._endNotices:Connect(function()L:Fire()end)local K=N:Connect(function()L:Fire()end)k=k or httpService:GenerateGUID(true)z.notices[k]={completeSignal=L;clearNoticeEvent=N}z.totalNotices+=1 z:_updateNotice()z.notified:Fire(k)L:Wait()l:Disconnect()K:Disconnect()L:Disconnect()z.totalNotices-=1 z.notices[k]=nil z:_updateNotice()end))()return z end function Icon._updateNotice(N)local k=true if N.totalNotices<1 then k=false end if not N.isSelected then if(#N.dropdownIcons>0 or#N.menuIcons>0)and N.totalNotices>0 then k=true end end if N.isSelected then if#N.dropdownIcons>0 or#N.menuIcons>0 then k=false end end local z=k and 0 or 1 N:set("\110\111\116\105\099\101\073\109\097\103\101\084\114\097\110\115\112\097\114\101\110\099\121",z)N:set("\110\111\116\105\099\101\084\101\120\116\084\114\097\110\115\112\097\114\101\110\099\121",z)N.instances.noticeLabel.Text=N.totalNotices<100 and N.totalNotices or"\057\057\043"end function Icon.clearNotices(N)N._endNotices:Fire()return N end function Icon.disableStateOverlay(k,N)if N==nil then N=true end local z=k.instances.iconOverlay z.Visible=not N return k end

function Icon:set(settingName, value, toggleState, setAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))

	-- Update the settings value
	if type(toggleState) == "string" then
		toggleState = toggleState:lower()
	end
	local previousValue = self:get(settingName, toggleState)
	local settingType = settingDetail.type
	if settingType == "toggleable" then
		local valuesToSet = {}
		if toggleState == "deselected" or toggleState == "selected" then
			table.insert(valuesToSet, toggleState)
		else
			table.insert(valuesToSet, "deselected")
			table.insert(valuesToSet, "selected")
			toggleState = nil
		end
		for i, v in pairs(valuesToSet) do
			settingDetail.values[v] = value
			if setAdditional ~= "_ignorePrevious" then
				settingDetail.additionalValues["previous_"..v] = previousValue
			end
			if type(setAdditional) == "string" then
				settingDetail.additionalValues[setAdditional.."_"..v] = previousValue
			end
		end
	else
		settingDetail.value = value
		if type(setAdditional) == "string" then
			if setAdditional ~= "_ignorePrevious" then
				settingDetail.additionalValues["previous"] = previousValue
			end
			settingDetail.additionalValues[setAdditional] = previousValue
		end
	end

	-- Check previous and new are not the same
	if previousValue == value then
		return self, "Value was already set"
	end

	-- Update appearances of associated instances
	local currentToggleState = self:getToggleState()
	if not self._updateAfterSettingAll and settingDetail.instanceNames and (currentToggleState == toggleState or toggleState == nil) then
		self:_update(settingName, currentToggleState, true)
	end

	-- Call any methods present
	if settingDetail.callMethods then
		for _, callMethod in pairs(settingDetail.callMethods) do
			callMethod(self, value, toggleState)
		end
	end
	
	-- Call any signals present
	if settingDetail.callSignals then
		for _, callSignal in pairs(settingDetail.callSignals) do
			callSignal:Fire()
		end
	end
	return self
end

function Icon:get(settingName, toggleState, getAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	local settingType = settingDetail.type
	if settingType == "toggleable" then
		toggleState = toggleState or self:getToggleState()
		local additionalValue = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional.."_"..toggleState]
		return settingDetail.values[toggleState], additionalValue
	end
	local additionalValue = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional]
	return settingDetail.value, additionalValue
end

function Icon:getToggleState(isSelected)
	isSelected = isSelected or self.isSelected
	return (isSelected and "selected") or "deselected"
end

function Icon:_update(settingName, toggleState, applyInstantly)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	toggleState = toggleState or self:getToggleState()
	local value = settingDetail.value or (settingDetail.values and settingDetail.values[toggleState])
	if value == nil then return end
	local tweenInfo = (applyInstantly and TweenInfo.new(0)) or self._settings.action.toggleTransitionInfo.value
	local propertyName = settingDetail.propertyName
	local invalidPropertiesTypes = {
		["string"] = true,
		["NumberSequence"] = true,
		["Text"] = true,
		["EnumItem"] = true,
		["ColorSequence"] = true,
	}
	local uniqueSetting = self._uniqueSettingsDictionary[settingName]
	for _, instanceName in pairs(settingDetail.instanceNames) do
		local instance = self.instances[instanceName]
		local propertyType = typeof(instance[propertyName])
		local cannotTweenProperty = invalidPropertiesTypes[propertyType]
		if uniqueSetting then
			uniqueSetting(settingName, instance, propertyName, value)
		elseif cannotTweenProperty then
			instance[propertyName] = value
		else
			tweenService:Create(instance, tweenInfo, {[propertyName] = value}):Play()
		end
		--
		if settingName == "iconSize" and instance[propertyName] ~= value then
			self.updated:Fire()
		end
		--
	end
end

function Icon:_updateAll(toggleState, applyInstantly)
	for settingName, settingDetail in pairs(self._settingsDictionary) do
		if settingDetail.instanceNames then
			self:_update(settingName, toggleState, applyInstantly)
		end
	end
end

function Icon:_updateStateOverlay(transparency, color)
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.BackgroundTransparency = transparency or 1
	stateOverlay.BackgroundColor3 = color or Color3.new(1, 1, 1)
end

function Icon:setTheme(theme, updateAfterSettingAll)
	self._updateAfterSettingAll = updateAfterSettingAll
	for settingsType, settingsDetails in pairs(theme) do
		if settingsType == "toggleable" then
			for settingName, settingValue in pairs(settingsDetails.deselected) do
				self:set(settingName, settingValue, "both")
			end
			for settingName, settingValue in pairs(settingsDetails.selected) do
				self:set(settingName, settingValue, "selected")
			end
		else
			for settingName, settingValue in pairs(settingsDetails) do
				self:set(settingName, settingValue)
			end
		end
	end
	self._updateAfterSettingAll = nil
	if updateAfterSettingAll then
		self:_updateAll()
	end
	return self
end

function Icon:setEnabled(bool)
	self.enabled = bool
	self.instances.iconContainer.Visible = bool
	self.updated:Fire()
	return self
end

function Icon:setName(string)
	self.name = string
	self.instances.iconContainer.Name = string
	return self
end

function Icon:_playClickSound()
	local clickSound = self.instances.clickSound
	if clickSound.SoundId ~= nil and #clickSound.SoundId > 0 and clickSound.Volume > 0 then
		local clickSoundCopy = clickSound:Clone()
		clickSoundCopy.Parent = clickSound.Parent
		clickSoundCopy:Play()
		debris:AddItem(clickSoundCopy, clickSound.TimeLength)
	end
end

function Icon:select(byIcon)
	if self.locked then return self end
	self.isSelected = true
	self:_setToggleItemsVisible(true, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
    self.selected:Fire()
    self.toggled:Fire(self.isSelected)
	return self
end

function Icon:deselect(byIcon)
	if self.locked then return self end
	self.isSelected = false
	self:_setToggleItemsVisible(false, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
    self.deselected:Fire()
    self.toggled:Fire(self.isSelected)
	return self
end

function Icon:notify(clearNoticeEvent, noticeId)
	coroutine.wrap(function()
		if not clearNoticeEvent then
			clearNoticeEvent = self.deselected
		end
		if self._parentIcon then
			self._parentIcon:notify(clearNoticeEvent)
		end
		
		local notifComplete = Signal.new()
		local endEvent = self._endNotices:Connect(function()
			notifComplete:Fire()
		end)
		local customEvent = clearNoticeEvent:Connect(function()
			notifComplete:Fire()
		end)
		
		noticeId = noticeId or httpService:GenerateGUID(true)
		self.notices[noticeId] = {
			completeSignal = notifComplete,
			clearNoticeEvent = clearNoticeEvent,
		}
		self.totalNotices += 1
		self:_updateNotice()

		self.notified:Fire(noticeId)
		notifComplete:Wait()
		
		endEvent:Disconnect()
		customEvent:Disconnect()
		notifComplete:Disconnect()
		
		self.totalNotices -= 1
		self.notices[noticeId] = nil
		self:_updateNotice()
	end)()
	return self
end

function Icon:_updateNotice()
	local enabled = true
	if self.totalNotices < 1 then
		enabled = false
	end
	-- Deselect
	if not self.isSelected then
		if (#self.dropdownIcons > 0 or #self.menuIcons > 0) and self.totalNotices > 0 then
			enabled = true
		end
	end
	-- Select
	if self.isSelected then
		if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
			enabled = false
		end
	end
	local value = (enabled and 0) or 1
	self:set("noticeImageTransparency", value)
	self:set("noticeTextTransparency", value)
	self.instances.noticeLabel.Text = (self.totalNotices < 100 and self.totalNotices) or "99+"
end

function Icon:clearNotices()
	self._endNotices:Fire()
	return self
end

function Icon:disableStateOverlay(bool)
	if bool == nil then
		bool = true
	end
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.Visible = not bool
	return self
end


