1 /*
2  * Copyright (c) 2021 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 "core/components/progress/render_bubble_progress.h"
17 
18 #include "core/components/progress/progress_theme.h"
19 
20 namespace OHOS::Ace {
21 namespace {
22 
23 constexpr double SIN_45 = 0.707;
24 constexpr double COS_45 = 0.707;
25 constexpr Color DARK_COLOR = Color(0xFF333333);
26 constexpr Color LIGHT_COLOR = Color(0xFF8A8A8A);
27 
28 } // namespace
29 
RenderBubbleProgress()30 RenderBubbleProgress::RenderBubbleProgress() : RenderNode(true) {}
31 
OnPostFlush()32 void RenderBubbleProgress::OnPostFlush()
33 {
34     static const int32_t totalTime = 8;
35     static const int32_t totalDuration = 4800;
36     RefPtr<CurveAnimation<double>> animation =
37         AceType::MakeRefPtr<CurveAnimation<double>>(0, totalTime, Curves::LINEAR);
38     animation->AddListener([weak = AceType::WeakClaim(this)](float progress) {
39         auto bubble = weak.Upgrade();
40         if (!bubble) {
41             return;
42         }
43         bubble->step_ = static_cast<int32_t>(progress);
44         float fraction = progress - bubble->step_;
45         auto evaluatorDarkToLight = AceType::MakeRefPtr<LinearEvaluator<Color>>();
46         bubble->lightToDark_ = evaluatorDarkToLight->Evaluate(Color(LIGHT_COLOR), Color(DARK_COLOR), fraction);
47         bubble->darkToLight_ = evaluatorDarkToLight->Evaluate(Color(DARK_COLOR), Color(LIGHT_COLOR), fraction);
48         bubble->MarkNeedRender();
49     });
50     animatorController_->AddInterpolator(animation);
51     animatorController_->SetDuration(totalDuration);
52     animatorController_->SetIteration(ANIMATION_REPEAT_INFINITE);
53     animatorController_->Play();
54     simulationPrepared_ = true;
55 }
56 
Update(const RefPtr<Component> & component)57 void RenderBubbleProgress::Update(const RefPtr<Component>& component)
58 {
59     if (!animatorController_) {
60         auto context = GetContext();
61         animatorController_ = CREATE_ANIMATOR(context);
62         auto pipelineContext = context.Upgrade();
63         if (!pipelineContext) {
64             LOGE("context is nullptr");
65             return;
66         }
67         pipelineContext->AddPostFlushListener(AceType::Claim(this));
68     }
69 
70     auto bubbleProgress = AceType::DynamicCast<BubbleProgressComponent>(component);
71     if (!bubbleProgress) {
72         LOGE("Update with nullptr");
73         return;
74     }
75     diameter_ = NormalizeToPx(bubbleProgress->GetDiameter());
76     maxCircleRadius_ = NormalizeToPx(bubbleProgress->GetBubbleRadius());
77     MarkNeedLayout();
78 }
79 
PerformLayout()80 void RenderBubbleProgress::PerformLayout()
81 {
82     // the diameter will be constrain by layout size.
83     Size layoutSize;
84     auto theme = GetTheme<ProgressTheme>();
85     if (!NearEqual(diameter_, 0.0)) {
86         layoutSize = GetLayoutParam().Constrain(Size(diameter_, diameter_));
87     } else {
88         if (GetLayoutParam().GetMaxSize().IsInfinite()) {
89             double defaultDiameter = NormalizeToPx(theme->GetBubbleDiameter());
90             layoutSize = Size(defaultDiameter, defaultDiameter);
91         } else {
92             layoutSize = GetLayoutParam().GetMaxSize();
93         }
94     }
95 
96     // radius is half of the height or width
97     radius_ = std::min(layoutSize.Height(), layoutSize.Width()) / 2.0;
98     center_ = Vertex(layoutSize.Width() / 2.0, layoutSize.Height() / 2.0);
99 
100     // based on law of sines, when the r1 : r2 > 4.83 : 1, the circle will never be overlapped.
101     maxCircleRadius_ = NearEqual(maxCircleRadius_, 0.0) ? NormalizeToPx(theme->GetBubbleRadius()) : maxCircleRadius_;
102     SetLayoutSize(layoutSize);
103     CalculateCirclePosition();
104 }
105 
CalculateCirclePosition()106 void RenderBubbleProgress::CalculateCirclePosition()
107 {
108     double radius = radius_ - maxCircleRadius_;
109     subCircleCenter_.clear();
110     // Add bottom right points
111     subCircleCenter_.push_back(center_ + Vertex(0.0, radius));
112     subCircleCenter_.push_back(center_ + Vertex(SIN_45 * radius, COS_45 * radius));
113     subCircleCenter_.push_back(center_ + Vertex(radius, 0.0));
114 
115     // Add top right points
116     subCircleCenter_.push_back(center_ + Vertex(COS_45 * radius, -1 * SIN_45 * radius));
117     subCircleCenter_.push_back(center_ + Vertex(0.0, -1 * radius));
118 
119     // Add top left points
120     subCircleCenter_.push_back(center_ + Vertex(-1 * SIN_45 * radius, -1 * COS_45 * radius));
121     subCircleCenter_.push_back(center_ + Vertex(-1 * radius, 0.0));
122 
123     // Add bottom left points
124     subCircleCenter_.push_back(center_ + Vertex(-1 * SIN_45 * radius, COS_45 * radius));
125 }
126 
OnVisibleChanged()127 void RenderBubbleProgress::OnVisibleChanged()
128 {
129     AnimationChanged();
130 }
131 
OnHiddenChanged(bool hidden)132 void RenderBubbleProgress::OnHiddenChanged(bool hidden)
133 {
134     AnimationChanged();
135 }
136 
AnimationChanged()137 void RenderBubbleProgress::AnimationChanged()
138 {
139     if (!simulationPrepared_) {
140         return;
141     }
142     if (GetVisible() && !GetHidden()) {
143         if (animatorController_) {
144             animatorController_->Play();
145         } else {
146             LOGI("fail to start progress animation");
147         }
148     } else {
149         if (animatorController_) {
150             animatorController_->Pause();
151         } else {
152             LOGI("fail to stop progress animation");
153         }
154     }
155 }
156 
OnAppShow()157 void RenderBubbleProgress::OnAppShow()
158 {
159     RenderNode::OnAppShow();
160     AnimationChanged();
161 }
162 
OnAppHide()163 void RenderBubbleProgress::OnAppHide()
164 {
165     RenderNode::OnAppHide();
166     AnimationChanged();
167 }
168 
169 }
170