• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_ng/pattern/loading_progress/loading_progress_modifier.h"
17 #include <algorithm>
18 
19 #include "base/geometry/arc.h"
20 #include "base/geometry/dimension.h"
21 #include "base/memory/ace_type.h"
22 #include "base/utils/utils.h"
23 #include "bridge/common/dom/dom_type.h"
24 #include "core/components/common/properties/animation_option.h"
25 #include "core/components/progress/progress_theme.h"
26 #include "core/components_ng/base/modifier.h"
27 #include "core/components_ng/pattern/loading_progress/loading_progress_utill.h"
28 #include "core/components_ng/pattern/refresh/refresh_animation_state.h"
29 #include "core/components_ng/render/animation_utils.h"
30 #include "core/components_ng/render/drawing.h"
31 #include "core/components_ng/render/drawing_prop_convertor.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 constexpr float TOTAL_ANGLE = 360.0f;
36 constexpr float ROTATEX = -116.0f;
37 constexpr float ROTATEY = 30.0f;
38 constexpr float ROTATEZ = 22.0f;
39 constexpr float COUNT = 50.0f;
40 constexpr float HALF = 0.5f;
41 constexpr float DOUBLE = 2.0f;
42 constexpr int32_t RING_ALPHA = 200;
43 constexpr int32_t TOTAL_POINTS_COUNT = 20;
44 constexpr int32_t TAIL_ANIAMTION_DURATION = 400;
45 constexpr int32_t TRANS_DURATION = 100;
46 constexpr float TOTAL_TAIL_LENGTH = 60.0f;
47 constexpr float TAIL_ALPHA_RATIO = 0.82f;
48 constexpr float INITIAL_SIZE_SCALE = 0.825f;
49 constexpr float INITIAL_OPACITY_SCALE = 0.7f;
50 constexpr float COMET_TAIL_ANGLE = 3.0f;
51 constexpr int32_t LOADING_DURATION = 1200;
52 constexpr float FOLLOW_START = 72.0f;
53 constexpr float FOLLOW_SPAN = 10.0f;
54 constexpr float FULL_COUNT = 100.0f;
55 constexpr float STAGE1 = 0.25f;
56 constexpr float STAGE2 = 0.65f;
57 constexpr float STAGE3 = 0.75f;
58 constexpr float STAGE4 = 0.85f;
59 constexpr float STAGE5 = 1.0f;
60 constexpr float OPACITY1 = 0.2f;
61 constexpr float OPACITY2 = 0.7f;
62 constexpr float OPACITY3 = 1.0f;
63 constexpr float SIZE_SCALE1 = 0.65f;
64 constexpr float SIZE_SCALE2 = 0.825f;
65 constexpr float SIZE_SCALE3 = 0.93f;
66 constexpr float MOVE_STEP = 0.06f;
67 constexpr float TRANS_OPACITY_SPAN = 0.3f;
68 constexpr float FULL_OPACITY = 255.0f;
69 constexpr float TWO = 2.0f;
70 } // namespace
LoadingProgressModifier(LoadingProgressOwner loadingProgressOwner)71 LoadingProgressModifier::LoadingProgressModifier(LoadingProgressOwner loadingProgressOwner)
72     : enableLoading_(AceType::MakeRefPtr<PropertyBool>(true)),
73       offset_(AceType::MakeRefPtr<PropertyOffsetF>(OffsetF())),
74       contentSize_(AceType::MakeRefPtr<PropertySizeF>(SizeF())),
75       date_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
76       color_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor::TRANSPARENT)),
77       centerDeviation_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
78       cometOpacity_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_OPACITY_SCALE)),
79       cometSizeScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_SIZE_SCALE)),
80       cometTailLen_(AceType::MakeRefPtr<AnimatablePropertyFloat>(TOTAL_TAIL_LENGTH)),
81       sizeScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(1.0f)), loadingProgressOwner_(loadingProgressOwner)
82 {
83     AttachProperty(enableLoading_);
84     AttachProperty(offset_);
85     AttachProperty(contentSize_);
86     AttachProperty(date_);
87     AttachProperty(color_);
88     AttachProperty(centerDeviation_);
89     AttachProperty(cometOpacity_);
90     AttachProperty(cometSizeScale_);
91     AttachProperty(cometTailLen_);
92     AttachProperty(sizeScale_);
93 };
94 
onDraw(DrawingContext & context)95 void LoadingProgressModifier::onDraw(DrawingContext& context)
96 {
97     if (!enableLoading_->Get()) {
98         return;
99     }
100     float date = date_->Get();
101     auto diameter = std::min(contentSize_->Get().Width(), contentSize_->Get().Height());
102     RingParam ringParam;
103     ringParam.strokeWidth = LoadingProgressUtill::GetRingStrokeWidth(diameter) * sizeScale_->Get();
104     ringParam.radius = LoadingProgressUtill::GetRingRadius(diameter) * sizeScale_->Get();
105     ringParam.movement =
106         (ringParam.radius * DOUBLE + ringParam.strokeWidth) * centerDeviation_->Get() * sizeScale_->Get();
107 
108     CometParam cometParam;
109     cometParam.radius = LoadingProgressUtill::GetCometRadius(diameter) * sizeScale_->Get();
110     cometParam.alphaScale = cometOpacity_->Get();
111     cometParam.sizeScale = cometSizeScale_->Get();
112     cometParam.pointCount = GetCometNumber();
113 
114     auto orbitRadius = LoadingProgressUtill::GetOrbitRadius(diameter) * sizeScale_->Get();
115     if (date > COUNT) {
116         DrawRing(context, ringParam);
117         DrawOrbit(context, cometParam, orbitRadius, date);
118     } else {
119         DrawOrbit(context, cometParam, orbitRadius, date);
120         DrawRing(context, ringParam);
121     }
122 }
123 
DrawRing(DrawingContext & context,const RingParam & ringParam)124 void LoadingProgressModifier::DrawRing(DrawingContext& context, const RingParam& ringParam)
125 {
126     auto& canvas = context.canvas;
127     canvas.Save();
128     RSPen pen;
129     auto ringColor = color_->Get();
130     auto pipeline = PipelineBase::GetCurrentContext();
131     CHECK_NULL_VOID(pipeline);
132     auto progressTheme = pipeline->GetTheme<ProgressTheme>();
133     CHECK_NULL_VOID(progressTheme);
134     auto defaultColor = progressTheme->GetLoadingColor();
135     if (ringColor.GetValue() == defaultColor.GetValue()) {
136         pen.SetColor(
137             ToRSColor(Color::FromARGB(RING_ALPHA, ringColor.GetRed(), ringColor.GetGreen(), ringColor.GetBlue())));
138     } else {
139         pen.SetColor(ToRSColor(
140             Color::FromARGB(ringColor.GetAlpha(), ringColor.GetRed(), ringColor.GetGreen(), ringColor.GetBlue())));
141     }
142     pen.SetWidth(ringParam.strokeWidth);
143     pen.SetAntiAlias(true);
144     canvas.AttachPen(pen);
145     canvas.DrawCircle(
146         { offset_->Get().GetX() + contentSize_->Get().Width() * HALF,
147             offset_->Get().GetY() + contentSize_->Get().Height() * HALF + ringParam.movement },
148         ringParam.radius);
149     canvas.DetachPen();
150     canvas.Restore();
151 }
152 
DrawOrbit(DrawingContext & context,const CometParam & cometParam,float orbitRadius,float date)153 void LoadingProgressModifier::DrawOrbit(
154     DrawingContext& context, const CometParam& cometParam, float orbitRadius, float date)
155 {
156     auto pointCounts = cometParam.pointCount;
157     auto& canvas = context.canvas;
158     float width = contentSize_->Get().Width();
159     float height = contentSize_->Get().Height();
160     double angle = TOTAL_ANGLE * date / FULL_COUNT;
161     RSCamera3D camera;
162     camera.Save();
163     camera.RotateYDegrees(ROTATEY);
164     camera.RotateXDegrees(ROTATEX);
165     camera.RotateZDegrees(ROTATEZ);
166     RSMatrix matrix;
167     camera.ApplyToMatrix(matrix);
168     camera.Restore();
169     auto center = RSPoint(offset_->Get().GetX() + width / 2, offset_->Get().GetY() + height / 2);
170     RSBrush brush;
171     brush.SetAntiAlias(true);
172     canvas.Save();
173     canvas.Translate(center.GetX(), center.GetY());
174     std::vector<RSPoint> points;
175     for (uint32_t i = 0; i < pointCounts; i++) {
176         RSPoint point;
177         float cometAngal = GetCurentCometAngle(angle, pointCounts - i, pointCounts);
178         float rad = cometAngal * PI_NUM / (TOTAL_ANGLE * HALF);
179         point.SetX(std::cos(rad) * orbitRadius);
180         point.SetY(-std::sin(rad) * orbitRadius);
181         points.push_back(point);
182     }
183     std::vector<RSPoint> distPoints(points.size());
184     matrix.MapPoints(distPoints, points, points.size());
185     auto cometColor = color_->Get();
186     float colorAlpha = cometColor.GetAlpha() / FULL_OPACITY;
187     auto baseAlpha = colorAlpha * cometParam.alphaScale;
188     for (uint32_t i = 0; i < distPoints.size(); i++) {
189         RSPoint pointCenter = distPoints[i];
190         if (cometColor.GetValue() == Color::FOREGROUND.GetValue()) {
191             brush.SetColor(ToRSColor(cometColor));
192         } else {
193             float setAlpha = GetCurentCometOpacity(baseAlpha, distPoints.size() - i, distPoints.size());
194             if (NearZero(setAlpha)) {
195                 continue;
196             }
197             brush.SetColor(
198                 ToRSColor(Color::FromRGBO(cometColor.GetRed(), cometColor.GetGreen(), cometColor.GetBlue(), setAlpha)));
199         }
200         canvas.AttachBrush(brush);
201         canvas.DrawCircle(pointCenter, cometParam.radius * cometParam.sizeScale);
202     }
203     canvas.DetachBrush();
204     canvas.Restore();
205 }
206 
StartRecycleRingAnimation()207 void LoadingProgressModifier::StartRecycleRingAnimation()
208 {
209     auto context = PipelineBase::GetCurrentContext();
210     CHECK_NULL_VOID(context);
211     auto previousStageCurve = AceType::MakeRefPtr<CubicCurve>(0.0f, 0.0f, 0.67f, 1.0f);
212     AnimationOption option;
213     option.SetDuration(isVisible_ ? LOADING_DURATION : 0);
214     option.SetCurve(previousStageCurve);
215     if (context->IsFormRender()) {
216         LOGI("LoadingProgress is restricted at runtime when form render");
217         option.SetIteration(1);
218     } else {
219         option.SetIteration(-1);
220     }
221     AnimationUtils::OpenImplicitAnimation(option, previousStageCurve, nullptr);
222     auto middleStageCurve = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.0f, 0.67f, 1.0f);
223     AnimationUtils::AddKeyFrame(
224         STAGE1, middleStageCurve, [weakCenterDeviation = AceType::WeakClaim(AceType::RawPtr(centerDeviation_))]() {
225             auto centerDeviation = weakCenterDeviation.Upgrade();
226             CHECK_NULL_VOID(centerDeviation);
227             centerDeviation->Set(-1 * MOVE_STEP);
228         });
229     auto latterStageCurve = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.0f, 1.0f, 1.0f);
230     AnimationUtils::AddKeyFrame(
231         STAGE3, latterStageCurve, [weakCenterDeviation = AceType::WeakClaim(AceType::RawPtr(centerDeviation_))]() {
232             auto centerDeviation = weakCenterDeviation.Upgrade();
233             CHECK_NULL_VOID(centerDeviation);
234             centerDeviation->Set(MOVE_STEP);
235         });
236     AnimationUtils::AddKeyFrame(
237         STAGE5, latterStageCurve, [weakCenterDeviation = AceType::WeakClaim(AceType::RawPtr(centerDeviation_))]() {
238             auto centerDeviation = weakCenterDeviation.Upgrade();
239             CHECK_NULL_VOID(centerDeviation);
240             centerDeviation->Set(0.0f);
241         });
242     AnimationUtils::CloseImplicitAnimation();
243 }
244 
StartRecycleCometAnimation()245 void LoadingProgressModifier::StartRecycleCometAnimation()
246 {
247     auto context = PipelineBase::GetCurrentContext();
248     CHECK_NULL_VOID(context);
249     auto curve = AceType::MakeRefPtr<LinearCurve>();
250     AnimationOption option;
251     option.SetDuration(isVisible_ ? LOADING_DURATION : 0);
252     option.SetCurve(curve);
253     if (context->IsFormRender()) {
254         LOGI("LoadingProgress is restricted at runtime when form render");
255         option.SetIteration(1);
256     } else {
257         option.SetIteration(-1);
258     }
259 
260     cometOpacity_->Set(OPACITY2);
261     AnimationUtils::OpenImplicitAnimation(option, curve, nullptr);
262     AnimationUtils::AddKeyFrame(STAGE1, curve,
263         [weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
264             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
265             auto cometOpacity = weakCometOpacity.Upgrade();
266             if (cometOpacity) {
267                 cometOpacity->Set(OPACITY1);
268             }
269             auto cometSizeScale = weakCometSizeScale.Upgrade();
270             if (cometSizeScale) {
271                 cometSizeScale->Set(SIZE_SCALE1);
272             }
273         });
274     AnimationUtils::AddKeyFrame(STAGE2, curve,
275         [weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
276             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
277             auto cometOpacity = weakCometOpacity.Upgrade();
278             if (cometOpacity) {
279                 cometOpacity->Set(OPACITY3);
280             }
281             auto cometSizeScale = weakCometSizeScale.Upgrade();
282             if (cometSizeScale) {
283                 cometSizeScale->Set(SIZE_SCALE3);
284             }
285         });
286     AnimationUtils::AddKeyFrame(STAGE3, curve,
287         [weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
288             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
289             auto cometOpacity = weakCometOpacity.Upgrade();
290             if (cometOpacity) {
291                 cometOpacity->Set(OPACITY3);
292             }
293             auto cometSizeScale = weakCometSizeScale.Upgrade();
294             if (cometSizeScale) {
295                 cometSizeScale->Set(1.0f);
296             }
297         });
298     AnimationUtils::AddKeyFrame(STAGE4, curve,
299         [weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
300             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
301             auto cometOpacity = weakCometOpacity.Upgrade();
302             if (cometOpacity) {
303                 cometOpacity->Set(OPACITY3);
304             }
305             auto cometSizeScale = weakCometSizeScale.Upgrade();
306             if (cometSizeScale) {
307                 cometSizeScale->Set(SIZE_SCALE3);
308             }
309         });
310     AnimationUtils::AddKeyFrame(STAGE5, curve,
311         [weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
312             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
313             auto cometOpacity = weakCometOpacity.Upgrade();
314             if (cometOpacity) {
315                 cometOpacity->Set(OPACITY2);
316             }
317             auto cometSizeScale = weakCometSizeScale.Upgrade();
318             if (cometSizeScale) {
319                 cometSizeScale->Set(SIZE_SCALE2);
320             }
321         });
322     AnimationUtils::CloseImplicitAnimation();
323 }
324 
StartCometTailAnimation()325 void LoadingProgressModifier::StartCometTailAnimation()
326 {
327     auto curve = AceType::MakeRefPtr<LinearCurve>();
328     AnimationOption option;
329     option.SetDuration(TAIL_ANIAMTION_DURATION);
330     option.SetIteration(1);
331     option.SetCurve(curve);
332     AnimationUtils::Animate(option, [weakCometTailLen = AceType::WeakClaim(AceType::RawPtr(cometTailLen_))]() {
333         auto cometTailLen = weakCometTailLen.Upgrade();
334         CHECK_NULL_VOID(cometTailLen);
335         cometTailLen->Set(TOTAL_TAIL_LENGTH);
336     });
337 }
338 
GetCurentCometOpacity(float baseOpacity,uint32_t index,uint32_t totalNumber)339 float LoadingProgressModifier::GetCurentCometOpacity(float baseOpacity, uint32_t index, uint32_t totalNumber)
340 {
341     return baseOpacity * std::pow(TAIL_ALPHA_RATIO, std::clamp(index, 1u, totalNumber) - 1);
342 }
343 
GetCurentCometAngle(float baseAngle,uint32_t index,uint32_t totalNumber)344 float LoadingProgressModifier::GetCurentCometAngle(float baseAngle, uint32_t index, uint32_t totalNumber)
345 {
346     return std::fmod((baseAngle - (std::clamp(index, 1u, totalNumber) - 1) * COMET_TAIL_ANGLE), TOTAL_ANGLE);
347 }
348 
GetCometNumber()349 uint32_t LoadingProgressModifier::GetCometNumber()
350 {
351     CHECK_NULL_RETURN(cometTailLen_, TOTAL_POINTS_COUNT);
352     return static_cast<uint32_t>(cometTailLen_->Get() / COMET_TAIL_ANGLE);
353 }
354 
StartRecycle()355 void LoadingProgressModifier::StartRecycle()
356 {
357     auto context = PipelineBase::GetCurrentContext();
358     CHECK_NULL_VOID(context);
359     if (isLoading_) {
360         return;
361     }
362     sizeScale_->Set(1.0f);
363     if (date_) {
364         isLoading_ = true;
365         date_->Set(0.0f);
366         AnimationOption option = AnimationOption();
367         RefPtr<Curve> curve = AceType::MakeRefPtr<LinearCurve>();
368         LOGD("Loading StartRecycle Visible %d", isVisible_);
369         option.SetDuration(isVisible_ ? LOADING_DURATION : 0);
370         option.SetDelay(0);
371         option.SetCurve(curve);
372         if (context->IsFormRender()) {
373             LOGI("LoadingProgress is restricted at runtime when form render");
374             option.SetIteration(1);
375         } else {
376             option.SetIteration(-1);
377         }
378         AnimationUtils::Animate(option, [weakDate = AceType::WeakClaim(AceType::RawPtr(date_))]() {
379             auto date = weakDate.Upgrade();
380             CHECK_NULL_VOID(date);
381             date->Set(FULL_COUNT);
382         });
383     }
384     cometOpacity_->Set(INITIAL_OPACITY_SCALE);
385     cometSizeScale_->Set(INITIAL_SIZE_SCALE);
386     // ring up and down shift animation
387     StartRecycleRingAnimation();
388     // comet's circle Color transparency and sizeScale animation
389     StartRecycleCometAnimation();
390 }
391 
StartTransToRecycleAnimation()392 void LoadingProgressModifier::StartTransToRecycleAnimation()
393 {
394     auto curve = AceType::MakeRefPtr<CubicCurve>(0.6f, 0.2f, 1.0f, 1.0f);
395     AnimationOption option;
396     option.SetDuration(TRANS_DURATION);
397     option.SetIteration(1);
398     option.SetCurve(curve);
399     AnimationUtils::Animate(
400         option,
401         [weakDate = AceType::WeakClaim(AceType::RawPtr(date_)),
402             weakCometOpacity = AceType::WeakClaim(AceType::RawPtr(cometOpacity_)),
403             weakCometSizeScale = AceType::WeakClaim(AceType::RawPtr(cometSizeScale_))]() {
404             auto date = weakDate.Upgrade();
405             if (date) {
406                 date->Set(FULL_COUNT);
407             }
408             auto cometOpacity = weakCometOpacity.Upgrade();
409             if (cometOpacity) {
410                 cometOpacity->Set(1.0 - TRANS_OPACITY_SPAN);
411             }
412             auto cometSizeScale = weakCometSizeScale.Upgrade();
413             if (cometSizeScale) {
414                 cometSizeScale->Set(INITIAL_SIZE_SCALE);
415             }
416         },
417         [weak = AceType::WeakClaim(this)]() {
418             auto modify = weak.Upgrade();
419             CHECK_NULL_VOID(modify);
420             modify->StartRecycle();
421         });
422     StartCometTailAnimation();
423 }
424 
ChangeRefreshFollowData(float refreshFollowRatio)425 void LoadingProgressModifier::ChangeRefreshFollowData(float refreshFollowRatio)
426 {
427     auto ratio = CorrectNormalize(refreshFollowRatio);
428     sizeScale_->Set(std::sqrt(TWO) * HALF + (1.0 - std::sqrt(TWO) * HALF) * ratio);
429     if (isLoading_) {
430         return;
431     }
432     CHECK_NULL_VOID(date_);
433     date_->Set(FOLLOW_START + FOLLOW_SPAN * ratio);
434     cometTailLen_->Set(COMET_TAIL_ANGLE);
435     cometOpacity_->Set(1.0f);
436     cometSizeScale_->Set(1.0f);
437 }
438 
CorrectNormalize(float originData)439 float LoadingProgressModifier::CorrectNormalize(float originData)
440 {
441     auto ratio = originData;
442     if (ratio < 0.0f) {
443         ratio = 0.0f;
444     }
445     if (ratio > 1.0f) {
446         ratio = 1.0f;
447     };
448     return ratio;
449 }
450 } // namespace OHOS::Ace::NG
451