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