--!strict --[=[ @class AnimatedHighlightStack ]=] local require = require(script.Parent.loader).load(script) local AnimatedHighlight = require("AnimatedHighlight") local AnimatedHighlightModel = require("AnimatedHighlightModel") local BaseObject = require("BaseObject") local DuckTypeUtils = require("DuckTypeUtils") local Maid = require("Maid") local Observable = require("Observable") local ObservableSortedList = require("ObservableSortedList") local Rx = require("Rx") local Signal = require("Signal") local ValueObject = require("ValueObject") local AnimatedHighlightStack = setmetatable({}, BaseObject) AnimatedHighlightStack.ClassName = "AnimatedHighlightStack" AnimatedHighlightStack.__index = AnimatedHighlightStack export type AnimatedHighlightStack = typeof(setmetatable( {} :: { _adornee: Instance, _defaultModelValues: AnimatedHighlightModel.AnimatedHighlightModel, _list: any, _currentModel: AnimatedHighlightModel.AnimatedHighlightModel, _highlight: AnimatedHighlight.AnimatedHighlight, _hasEntries: ValueObject.ValueObject, maid: Maid.Maid, Done: Signal.Signal<()>, Destroying: Signal.Signal<()>, }, {} :: typeof({ __index = AnimatedHighlightStack }) )) & BaseObject.BaseObject function AnimatedHighlightStack.new(adornee: Instance, defaultModelValues): AnimatedHighlightStack local self: AnimatedHighlightStack = setmetatable(BaseObject.new() :: any, AnimatedHighlightStack) self._adornee = assert(adornee, "No adornee") self._defaultModelValues = assert(defaultModelValues, "No defaultModelValues") self._list = self._maid:Add(ObservableSortedList.new()) self._currentModel = self._maid:Add(AnimatedHighlightModel.new()) self._hasEntries = self._maid:Add(ValueObject.new(false, "boolean")) self.Done = self._maid:Add(Signal.new()) self._maid:GiveTask(self._list :ObserveCount() :Pipe({ Rx.switchMap(function(count) if count == 0 then return Rx.of(nil) :: any else return self._list:ObserveAtIndex(count) end end) :: any, Rx.distinct() :: any, }) :Subscribe(function(currentModel) if currentModel then self._maid._current = self:_setupModel(currentModel) self._hasEntries.Value = true else self._hasEntries.Value = false self._maid._current = nil end end)) self:_setupHighlight() self._maid:GiveTask(self._hasEntries:Observe():Subscribe(function(isEnabled) if isEnabled then self._highlight:Show() self._maid._done = nil else self._highlight:Hide() self._maid._done = task.delay(1, function() self.Done:Fire() end) end end)) self.Destroying = Signal.new() self._maid:GiveTask(function() self.Destroying:Fire() self.Destroying:Destroy() end) return self end --[=[ Returns true if the value is an animated highlight stack @param value any @return boolean ]=] function AnimatedHighlightStack.isAnimatedHighlightStack(value: any): boolean return DuckTypeUtils.isImplementation(AnimatedHighlightStack, value) end --[=[ Sets the stacks initial properties to mirror the given stacks @param source AnimatedHighlightStack ]=] function AnimatedHighlightStack:SetPropertiesFrom(source: AnimatedHighlightStack) assert(AnimatedHighlightStack.isAnimatedHighlightStack(source), "Bad source") self._highlight:SetPropertiesFrom(source._highlight) end --[=[ @return Observable ]=] function AnimatedHighlightStack:ObserveHasEntries(): Observable.Observable return self._hasEntries:Observe() end function AnimatedHighlightStack:_setupHighlight() local maid = Maid.new() self._highlight = AnimatedHighlight.new() self._highlight:SetAdornee(self._adornee) self._maid:GiveTask(self._highlight) maid:GiveTask(self._currentModel.HighlightDepthMode:Observe():Subscribe(function(value) if value then self._highlight:SetHighlightDepthMode(value) end end)) maid:GiveTask(self._currentModel.FillColor:Observe():Subscribe(function(value, doNotAnimate) if value then self._highlight:SetFillColor(value, doNotAnimate) end end)) maid:GiveTask(self._currentModel.OutlineColor:Observe():Subscribe(function(value, doNotAnimate) if value then self._highlight:SetOutlineColor(value, doNotAnimate) end end)) maid:GiveTask(self._currentModel.FillTransparency:Observe():Subscribe(function(value, doNotAnimate) if value then self._highlight:SetFillTransparency(value, doNotAnimate) end end)) maid:GiveTask(self._currentModel.OutlineTransparency:Observe():Subscribe(function(value, doNotAnimate) if value then self._highlight:SetOutlineTransparency(value, doNotAnimate) end end)) maid:GiveTask(self._currentModel.ColorSpeed:Observe():Subscribe(function(value) if value then self._highlight:SetColorSpeed(value) end end)) maid:GiveTask(self._currentModel.Speed:Observe():Subscribe(function(value) if value then self._highlight:SetSpeed(value) end end)) maid:GiveTask(self._currentModel.TransparencySpeed:Observe():Subscribe(function(value) if value then self._highlight:SetTransparencySpeed(value) end end)) return maid end function AnimatedHighlightStack:_setupModel(model: AnimatedHighlightModel.AnimatedHighlightModel) local maid = Maid.new() -- TODO: Default to default value instead local function filterNil(observeDefaultValue, observable) return observable:Pipe({ Rx.switchMap(function(value): any if value ~= nil then return Rx.of(value) else return observeDefaultValue end end) :: any, Rx.where(function(value) return value ~= nil end) :: any, }) end maid:GiveTask( self._currentModel.HighlightDepthMode:Mount( filterNil(self._defaultModelValues.HighlightDepthMode:Observe(), model.HighlightDepthMode:Observe()) ) ) maid:GiveTask( self._currentModel.FillColor:Mount( filterNil(self._defaultModelValues.FillColor:Observe(), model.FillColor:Observe()) ) ) maid:GiveTask( self._currentModel.OutlineColor:Mount( filterNil(self._defaultModelValues.OutlineColor:Observe(), model.OutlineColor:Observe()) ) ) maid:GiveTask( self._currentModel.FillTransparency:Mount( filterNil(self._defaultModelValues.FillTransparency:Observe(), model.FillTransparency:Observe()) ) ) maid:GiveTask( self._currentModel.OutlineTransparency:Mount( filterNil(self._defaultModelValues.OutlineTransparency:Observe(), model.OutlineTransparency:Observe()) ) ) maid:GiveTask( self._currentModel.Speed:Mount(filterNil(self._defaultModelValues.Speed:Observe(), model.Speed:Observe())) ) maid:GiveTask( self._currentModel.TransparencySpeed:Mount( filterNil(self._defaultModelValues.TransparencySpeed:Observe(), model.TransparencySpeed:Observe()) ) ) return maid end --[=[ Gets a new handle for the stack @param observeScore Observable @return AnimatedHighlightModel ]=] function AnimatedHighlightStack:GetHandle( observeScore: Observable.Observable ): AnimatedHighlightModel.AnimatedHighlightModel assert(observeScore, "No observeScore") local maid = Maid.new() local model = AnimatedHighlightModel.new() maid:GiveTask(model) self._maid[maid] = maid maid:GiveTask(function() self._maid[maid] = nil end) maid:GiveTask(self._list:Add(model, observeScore)) maid:GiveTask(model.Destroying:Connect(function() self._maid[maid] = nil end)) return model end return AnimatedHighlightStack