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