1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "base/geometry/animatable_dimension.h"
17#include "core/event/ace_event_helper.h"
18
19namespace OHOS::Ace {
20AnimatableDimension& AnimatableDimension::operator=(const Dimension& newDimension)
21{
22    ResetAnimatableDimension();
23    Dimension& dimension = *this;
24    dimension = newDimension;
25    return *this;
26}
27
28AnimatableDimension& AnimatableDimension::operator=(const CalcDimension& newDimension)
29{
30    ResetAnimatableDimension();
31    CalcDimension& dimension = *this;
32    dimension = newDimension;
33    return *this;
34}
35
36AnimatableDimension& AnimatableDimension::operator=(const AnimatableDimension& newDimension)
37{
38    SetUnit(newDimension.Unit());
39    SetAnimationOption(newDimension.GetAnimationOption());
40    auto pipelineContext = context_.Upgrade();
41    if (!animationCallback_ || !pipelineContext) {
42        if (newDimension.Unit() == DimensionUnit::CALC) {
43            SetCalcValue(newDimension.CalcValue());
44        } else {
45            SetValue(newDimension.Value());
46        }
47        return *this;
48    }
49    AnimationOption explicitAnim = pipelineContext->GetExplicitAnimationOption();
50    if (explicitAnim.IsValid()) {
51        SetAnimationOption(explicitAnim);
52        AnimateTo(newDimension.Value());
53    } else if (animationOption_.IsValid()) {
54        AnimateTo(newDimension.Value());
55    } else {
56        ResetController();
57        if (newDimension.Unit() == DimensionUnit::CALC) {
58            SetCalcValue(newDimension.CalcValue());
59        } else {
60            SetValue(newDimension.Value());
61        }
62    }
63    isFirstAssign_ = false;
64    return *this;
65}
66
67void AnimatableDimension::AnimateTo(double endValue)
68{
69    if (isFirstAssign_) {
70        isFirstAssign_ = false;
71        SetValue(endValue);
72        return;
73    }
74    if (NearEqual(Value(), endValue) && !evaluator_) {
75        return;
76    }
77    ResetController();
78    if (!animationController_) {
79        animationController_ = CREATE_ANIMATOR(context_);
80    }
81    RefPtr<CurveAnimation<double>> animation =
82        AceType::MakeRefPtr<CurveAnimation<double>>(Value(), endValue, animationOption_.GetCurve());
83    if (evaluator_) {
84        animation->SetEvaluator(evaluator_);
85    }
86    animation->AddListener(std::bind(&AnimatableDimension::OnAnimationCallback, this, std::placeholders::_1));
87
88    animationController_->AddInterpolator(animation);
89    auto onFinishEvent = animationOption_.GetOnFinishEvent();
90    if (onFinishEvent) {
91        animationController_->AddStopListener([onFinishEvent, weakContext = context_] {
92            auto context = weakContext.Upgrade();
93            if (context) {
94                context->PostAsyncEvent(onFinishEvent, "ArkUIAnimatableDimensionFinishEvent");
95            }
96        });
97    }
98    if (stopCallback_) {
99        animationController_->AddStopListener(stopCallback_);
100    }
101    animationController_->SetDuration(animationOption_.GetDuration());
102    animationController_->SetStartDelay(animationOption_.GetDelay());
103    animationController_->SetIteration(animationOption_.GetIteration());
104    animationController_->SetTempo(animationOption_.GetTempo());
105    animationController_->SetAnimationDirection(animationOption_.GetAnimationDirection());
106    animationController_->SetFillMode(FillMode::FORWARDS);
107    animationController_->SetAllowRunningAsynchronously(animationOption_.GetAllowRunningAsynchronously());
108    animationController_->Play();
109}
110
111void AnimatableDimension::ResetController()
112{
113    if (animationController_) {
114        if (!animationController_->IsStopped()) {
115            animationController_->Stop();
116        }
117        animationController_->ClearInterpolators();
118        animationController_->ClearAllListeners();
119        animationController_.Reset();
120    }
121}
122
123void AnimatableDimension::OnAnimationCallback(double value)
124{
125    SetValue(value);
126    if (animationCallback_) {
127        animationCallback_();
128    }
129}
130
131void AnimatableDimension::MoveTo(double target)
132{
133    SetValue(target);
134    isFirstAssign_ = false;
135}
136
137void AnimatableDimension::ResetAnimatableDimension()
138{
139    isFirstAssign_ = true;
140    animationOption_ = AnimationOption();
141    animationController_ = nullptr;
142    context_ = nullptr;
143    animationCallback_ = nullptr;
144}
145} // namespace OHOS::Ace
146