• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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/swiper_indicator/dot_indicator/dot_indicator_modifier.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/animation/spring_curve.h"
20 #include "core/components_ng/render/animation_utils.h"
21 #include "core/components_ng/render/drawing.h"
22 #include "core/components_ng/render/paint_property.h"
23 
24 namespace OHOS::Ace::NG {
25 namespace {
26 constexpr int32_t POINT_HOVER_ANIMATION_DURATION = 100;
27 constexpr int32_t COMPONENT_DILATE_ANIMATION_DURATION = 250;
28 constexpr int32_t COMPONENT_SHRINK_ANIMATION_DURATION = 300;
29 constexpr int32_t MOUSE_PRESS_ANIMATION_DURATION = 250;
30 
31 constexpr float BLACK_POINT_CENTER_BEZIER_CURVE_VELOCITY = 0.4f;
32 constexpr float CENTER_BEZIER_CURVE_MASS = 0.0f;
33 constexpr float CENTER_BEZIER_CURVE_STIFFNESS = 1.0f;
34 constexpr float CENTER_BEZIER_CURVE_DAMPING = 1.0f;
35 constexpr uint32_t ITEM_HALF_WIDTH = 0;
36 constexpr uint32_t ITEM_HALF_HEIGHT = 1;
37 constexpr uint32_t SELECTED_ITEM_HALF_WIDTH = 2;
38 constexpr uint32_t SELECTED_ITEM_HALF_HEIGHT = 3;
39 constexpr float TOUCH_BOTTOM_CURVE_VELOCITY = 0.1f;
40 constexpr float TOUCH_BOTTOM_CURVE_MASS = 0.2f;
41 constexpr float TOUCH_BOTTOM_CURVE_STIFFNESS = 0.48f;
42 constexpr float TOUCH_BOTTOM_CURVE_DAMPING = 1.0f;
43 constexpr float TOUCH_BOTTOM_BACKGROUND_WIDTH_MULTIPLE = 1.225f;
44 constexpr float TOUCH_BOTTOM_BACKGROUND_HEIGHT_MULTIPLE = 0.8f;
45 constexpr float TOUCH_BOTTOM_DOT_WIDTH_MULTIPLE = 0.0125f;
46 constexpr int32_t DEFAULT_TOUCH_BOTTOM_ANIMATION_DURATION = 200;
47 constexpr int32_t DEFAULT_OPACITY_ANIMATION_DURATION = 100;
48 constexpr float LOOP_TRANSLATE_DURATION_PERCENT = 0.5f;
49 constexpr float LOOP_OPACITY_DURATION_PERCENT = 0.25f;
50 constexpr uint8_t TARGET_ALPHA = 255;
51 constexpr int32_t BLACK_POINT_DURATION = 400;
52 constexpr float DEFAULT_MINIMUM_AMPLITUDE_PX = 1.0f;
53 constexpr float HALF_FLOAT = 0.5f;
54 constexpr float TWO_FLOAT = 2.0f;
55 constexpr int32_t LONG_POINT_STEP_TWO = 2;
56 constexpr int32_t LONG_POINT_STEP_THREE = 3;
57 constexpr int32_t LONG_POINT_STEP_FOUR = 4;
58 // velocity:0, mass:1, stiffness:81, damping:11
59 const auto LONG_POINT_DEFAULT_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0, 1, 81, 11);
60 const auto LONG_POINT_STEP_TWO_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0, 1, 108, 16);
61 const auto LONG_POINT_STEP_THREE_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0, 1, 128, 18);
62 const auto LONG_POINT_STEP_FOUR_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0, 1, 128, 20);
63 const auto LONG_POINT_STEP_FIVE_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0, 1, 148, 28);
64 constexpr float SMALLEST_POINT_RATIO = 1.0f / 3.0f;
65 constexpr float SECOND_SMALLEST_POINT_RATIO = 2.0f / 3.0f;
66 constexpr int32_t OVERLONG_SMALL_COUNT = 2;
67 } // namespace
68 
onDraw(DrawingContext & context)69 void DotIndicatorModifier::onDraw(DrawingContext& context)
70 {
71     ContentProperty contentProperty;
72     contentProperty.backgroundColor = backgroundColor_->Get().ToColor();
73     contentProperty.vectorBlackPointCenterX = vectorBlackPointCenterX_->Get();
74     contentProperty.longPointLeftCenterX = longPointLeftCenterX_->Get();
75     contentProperty.longPointRightCenterX = longPointRightCenterX_->Get();
76     contentProperty.normalToHoverPointDilateRatio = normalToHoverPointDilateRatio_->Get();
77     contentProperty.hoverToNormalPointDilateRatio = hoverToNormalPointDilateRatio_->Get();
78     contentProperty.longPointDilateRatio = longPointDilateRatio_->Get();
79     contentProperty.indicatorPadding = indicatorPadding_->Get();
80     contentProperty.indicatorMargin = indicatorMargin_->Get();
81     contentProperty.itemHalfSizes = itemHalfSizes_->Get();
82     SetFocusedAndSelectedColor(contentProperty);
83     PaintBackground(context, contentProperty);
84     PaintContent(context, contentProperty);
85 }
86 
SetFocusedAndSelectedColor(ContentProperty & contentProperty)87 void DotIndicatorModifier::SetFocusedAndSelectedColor(ContentProperty& contentProperty)
88 {
89     auto indicatorTheme = GetSwiperIndicatorTheme();
90     CHECK_NULL_VOID(indicatorTheme);
91     paddingSide_ = indicatorTheme->GetIndicatorPaddingDot();
92     scaleIndicator_ = indicatorTheme->GetIndicatorScale();
93     Color currentSelectedColor = selectedColor_->Get().ToColor();
94     Color currentUnselectedColor = unselectedColor_->Get();
95     if (isFocused_->Get()) {
96         originalUnselectColor_ = (indicatorTheme->GetColor() == currentUnselectedColor)
97                                      ? indicatorTheme->GetFocusUnSelectedColor()
98                                      : currentUnselectedColor;
99         originalSelectColor_ = (indicatorTheme->GetSelectedColor() == currentSelectedColor)
100                                    ? indicatorTheme->GetFocusedSelectedColor()
101                                    : currentSelectedColor;
102         contentProperty.backgroundColor = indicatorTheme->GetFocusedBgColor();
103     } else {
104         originalUnselectColor_ = currentUnselectedColor;
105         originalSelectColor_ = currentSelectedColor;
106         contentProperty.backgroundColor = backgroundColor_->Get().ToColor();
107     }
108 }
109 
PaintBackground(DrawingContext & context,const ContentProperty & contentProperty,int32_t maxDisplayCount,bool isBindIndicator)110 void DotIndicatorModifier::PaintBackground(
111     DrawingContext& context, const ContentProperty& contentProperty, int32_t maxDisplayCount, bool isBindIndicator)
112 {
113     CHECK_NULL_VOID(contentProperty.backgroundColor.GetAlpha());
114     auto itemWidth = contentProperty.itemHalfSizes[ITEM_HALF_WIDTH] * 2;
115     auto itemHeight = contentProperty.itemHalfSizes[ITEM_HALF_HEIGHT] * 2;
116     auto selectedItemWidth = contentProperty.itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * 2;
117     auto selectedItemHeight = contentProperty.itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT] * 2;
118     auto pointNumber = static_cast<float>(contentProperty.vectorBlackPointCenterX.size());
119     float allPointDiameterSum = itemWidth * static_cast<float>(pointNumber + 1);
120     if (isCustomSize_) {
121         allPointDiameterSum = itemWidth * static_cast<float>(pointNumber - 1) + selectedItemWidth;
122     }
123     float allPointSpaceSum = static_cast<float>(GetIndicatorDotItemSpace().ConvertToPx()) * (pointNumber - 1);
124 
125     if (maxDisplayCount > 0 && isBindIndicator) {
126         allPointSpaceSum = static_cast<float>(GetIndicatorDotItemSpace().ConvertToPx()) * (maxDisplayCount - 1);
127         allPointDiameterSum = itemWidth * (maxDisplayCount - OVERLONG_SMALL_COUNT - 1) + selectedItemWidth +
128                               itemWidth * SECOND_SMALLEST_POINT_RATIO + itemWidth * SMALLEST_POINT_RATIO;
129     }
130 
131     // Background necessary property
132     float rectWidth =
133         contentProperty.indicatorPadding + allPointDiameterSum + allPointSpaceSum + contentProperty.indicatorPadding;
134     auto indicatorTheme = GetSwiperIndicatorTheme();
135     CHECK_NULL_VOID(indicatorTheme);
136     auto indicatorHeightPadding = indicatorTheme->GetIndicatorBgHeight().ConvertToPx();
137     float rectHeight = indicatorHeightPadding + itemHeight + indicatorHeightPadding;
138     if (selectedItemHeight > itemHeight) {
139         rectHeight = indicatorHeightPadding + selectedItemHeight + indicatorHeightPadding;
140     }
141 
142     auto [rectLeft, rectRight, rectTop, rectBottom] =
143         CalcAndAdjustIndicatorPaintRect(contentProperty, rectWidth, rectHeight);
144     // Paint background
145     RSCanvas& canvas = context.canvas;
146     RSBrush brush;
147     brush.SetAntiAlias(true);
148     brush.SetColor(ToRSColor(contentProperty.backgroundColor));
149     canvas.AttachBrush(brush);
150     auto radius = axis_ == Axis::HORIZONTAL ? rectHeight : rectWidth;
151     canvas.DrawRoundRect({ { rectLeft, rectTop, rectRight, rectBottom }, radius, radius });
152     canvas.DetachBrush();
153 }
154 
CalcAndAdjustIndicatorPaintRect(const ContentProperty & contentProperty,float & rectWidth,float & rectHeight)155 std::tuple<float, float, float, float> DotIndicatorModifier::CalcAndAdjustIndicatorPaintRect(
156     const ContentProperty& contentProperty, float& rectWidth, float& rectHeight)
157 {
158     auto widthChangeValue = (backgroundWidthDilateRatio_->Get() - 1.0f) * rectWidth;
159     auto heightChangeValue = (1.0f - backgroundHeightDilateRatio_->Get()) * rectHeight;
160     if (axis_ == Axis::VERTICAL) {
161         std::swap(widthChangeValue, heightChangeValue);
162     }
163     // Property to get the rectangle offset
164     float rectLeft =
165         axis_ == Axis::HORIZONTAL ? contentProperty.indicatorMargin.GetX() : contentProperty.indicatorMargin.GetY();
166     float rectTop =
167         axis_ == Axis::HORIZONTAL ? contentProperty.indicatorMargin.GetY() : contentProperty.indicatorMargin.GetX();
168     // Adapter circle and rect
169     float rectRight = rectLeft + (axis_ == Axis::HORIZONTAL ? rectWidth : rectHeight);
170     float rectBottom = rectTop + (axis_ == Axis::HORIZONTAL ? rectHeight : rectWidth);
171 
172     if (axis_ == Axis::HORIZONTAL) {
173         if (touchBottomType_ == TouchBottomType::START) {
174             rectLeft -= widthChangeValue;
175         }
176         if (touchBottomType_ == TouchBottomType::END) {
177             rectRight += widthChangeValue;
178         }
179         rectTop = rectTop + heightChangeValue * 0.5f;
180         rectBottom = rectBottom - heightChangeValue * 0.5f;
181         rectHeight -= heightChangeValue;
182     } else {
183         if (touchBottomType_ == TouchBottomType::START) {
184             rectTop -= heightChangeValue;
185         }
186         if (touchBottomType_ == TouchBottomType::END) {
187             rectBottom += heightChangeValue;
188         }
189         rectLeft = rectLeft + widthChangeValue * 0.5f;
190         rectRight = rectRight - widthChangeValue * 0.5f;
191         rectWidth -= widthChangeValue;
192     }
193 
194     return { rectLeft, rectRight, rectTop, rectBottom };
195 }
196 
GetTouchBottomCenterX(ContentProperty & contentProperty)197 std::pair<float, float> DotIndicatorModifier::GetTouchBottomCenterX(ContentProperty& contentProperty)
198 {
199     float leftCenterX = contentProperty.longPointLeftCenterX;
200     float rightCenterX = contentProperty.longPointRightCenterX;
201 
202     if (contentProperty.vectorBlackPointCenterX.empty()) {
203         return { leftCenterX, rightCenterX };
204     }
205     auto totalCount = contentProperty.vectorBlackPointCenterX.size();
206     // 2.0 means get the long point radius
207     float radius = (rightCenterX - leftCenterX) / 2.0f;
208     bool isLeftTouchBottom = (currentIndex_ == static_cast<int32_t>(totalCount) - 1);
209     bool isRightTouchBottom = (currentIndex_ == 0);
210 
211     if ((animationState_ == TouchBottomAnimationStage::STAGE_SHRINKT_TO_BLACK_POINT && isLeftTouchBottom) ||
212         (animationState_ == TouchBottomAnimationStage::STAGE_EXPAND_TO_LONG_POINT && isRightTouchBottom)) {
213         leftCenterX = contentProperty.vectorBlackPointCenterX[0] - radius;
214         rightCenterX = contentProperty.vectorBlackPointCenterX[0] + radius;
215     } else if ((animationState_ == TouchBottomAnimationStage::STAGE_EXPAND_TO_LONG_POINT && isLeftTouchBottom) ||
216         (animationState_ == TouchBottomAnimationStage::STAGE_SHRINKT_TO_BLACK_POINT && isRightTouchBottom)) {
217         leftCenterX = contentProperty.vectorBlackPointCenterX[totalCount - 1] - radius;
218         rightCenterX = contentProperty.vectorBlackPointCenterX[totalCount - 1] + radius;
219     }
220 
221     return { leftCenterX, rightCenterX };
222 }
223 
PaintContent(DrawingContext & context,ContentProperty & contentProperty)224 void DotIndicatorModifier::PaintContent(DrawingContext& context, ContentProperty& contentProperty)
225 {
226     RSCanvas& canvas = context.canvas;
227     OffsetF selectedCenter = {};
228     auto totalCount = contentProperty.vectorBlackPointCenterX.size();
229     if (totalCount == 0 && NearZero(contentProperty.longPointLeftCenterX) &&
230         NearZero(contentProperty.longPointRightCenterX)) {
231         return;
232     }
233 
234     for (size_t i = 0; i < totalCount; ++i) {
235         LinearVector<float> itemHalfSizes = GetItemHalfSizes(i, contentProperty);
236         OffsetF center = { contentProperty.vectorBlackPointCenterX[i], centerY_ };
237         if (static_cast<int32_t>(i) != currentIndex_) {
238             PaintUnselectedIndicator(canvas, center, itemHalfSizes, false, LinearColor(originalUnselectColor_));
239         } else {
240             selectedCenter = center;
241             PaintUnselectedIndicator(canvas, center, itemHalfSizes, isCustomSize_,
242                 LinearColor(originalUnselectColor_));
243         }
244     }
245 
246     auto [leftCenterX, rightCenterX] = GetTouchBottomCenterX(contentProperty);
247 
248     OffsetF leftCenter = { leftCenterX, centerY_ };
249     OffsetF rightCenter = { rightCenterX, centerY_ };
250     OffsetF centerDistance = rightCenter - leftCenter;
251     OffsetF centerDilateDistance = centerDistance * contentProperty.longPointDilateRatio;
252     leftCenter -= (centerDilateDistance - centerDistance) * 0.5;
253     rightCenter += (centerDilateDistance - centerDistance) * 0.5;
254     PaintSelectedIndicator(canvas, leftCenter, rightCenter,
255         contentProperty.itemHalfSizes * contentProperty.longPointDilateRatio);
256 
257     bool isLeftTouchBottom = (currentIndex_ == static_cast<int32_t>(totalCount) - 1);
258     bool isRightTouchBottom = (currentIndex_ == 0);
259     bool isTouchBottom = (isLeftTouchBottom || isRightTouchBottom);
260     if (!isTouchBottom || totalCount == 0 || !isTouchBottomLoop_) {
261         return;
262     }
263 
264     size_t index = 0;
265     if (isRightTouchBottom) {
266         index = totalCount - 1;
267     }
268     LinearVector<float> itemHalfSizes = GetItemHalfSizes(index, contentProperty);
269     OffsetF center = { contentProperty.vectorBlackPointCenterX[index], centerY_ };
270     PaintUnselectedIndicator(canvas, center, itemHalfSizes, false, touchBottomPointColor_->Get());
271 }
272 
GetItemHalfSizes(size_t index,ContentProperty & contentProperty)273 LinearVector<float> DotIndicatorModifier::GetItemHalfSizes(size_t index, ContentProperty& contentProperty)
274 {
275     if (normalToHoverIndex_.has_value() && normalToHoverIndex_ == index) {
276         return contentProperty.itemHalfSizes * contentProperty.normalToHoverPointDilateRatio;
277     }
278     if (hoverToNormalIndex_.has_value() && hoverToNormalIndex_ == index) {
279         return contentProperty.itemHalfSizes * contentProperty.hoverToNormalPointDilateRatio;
280     }
281     return contentProperty.itemHalfSizes;
282 }
283 
PaintUnselectedIndicator(RSCanvas & canvas,const OffsetF & center,const LinearVector<float> & itemHalfSizes,bool currentIndexFlag,const LinearColor & indicatorColor)284 void DotIndicatorModifier::PaintUnselectedIndicator(RSCanvas& canvas, const OffsetF& center,
285     const LinearVector<float>& itemHalfSizes, bool currentIndexFlag, const LinearColor& indicatorColor)
286 {
287     RSBrush brush;
288     brush.SetAntiAlias(true);
289     brush.SetColor(ToRSColor(indicatorColor));
290     canvas.AttachBrush(brush);
291     if (!NearEqual(itemHalfSizes[ITEM_HALF_WIDTH], itemHalfSizes[ITEM_HALF_HEIGHT]) || currentIndexFlag ||
292         !isCustomSize_) {
293         float rectItemWidth = itemHalfSizes[ITEM_HALF_WIDTH] * 2;
294         float rectItemHeight = itemHalfSizes[ITEM_HALF_HEIGHT] * 2;
295         float rectLeft =
296             (axis_ == Axis::HORIZONTAL ? center.GetX() - rectItemWidth * 0.5 : center.GetY() - rectItemHeight * 0.5);
297         float rectTop =
298             (axis_ == Axis::HORIZONTAL ? center.GetY() - rectItemHeight * 0.5 : center.GetX() - rectItemWidth * 0.5);
299         float rectRight =
300             (axis_ == Axis::HORIZONTAL ? center.GetX() + rectItemWidth * 0.5 : center.GetY() + rectItemHeight * 0.5);
301         float rectBottom =
302             (axis_ == Axis::HORIZONTAL ? center.GetY() + rectItemHeight * 0.5 : center.GetX() + rectItemWidth * 0.5);
303 
304         if (rectItemHeight > rectItemWidth || !isCustomSize_) {
305             canvas.DrawRoundRect({ { rectLeft, rectTop, rectRight, rectBottom }, rectItemWidth, rectItemWidth });
306         } else if (rectItemHeight < rectItemWidth) {
307             canvas.DrawRoundRect({ { rectLeft, rectTop, rectRight, rectBottom }, rectItemHeight, rectItemHeight });
308         } else {
309             float customPointX = axis_ == Axis::HORIZONTAL ? center.GetX() : center.GetY();
310             float customPointY = axis_ == Axis::HORIZONTAL ? center.GetY() : center.GetX();
311             canvas.DrawCircle({ customPointX, customPointY }, rectItemHeight * 0.5);
312         }
313     } else {
314         float pointX = axis_ == Axis::HORIZONTAL ? center.GetX() : center.GetY();
315         float pointY = axis_ == Axis::HORIZONTAL ? center.GetY() : center.GetX();
316         canvas.DrawCircle({ pointX, pointY }, itemHalfSizes[ITEM_HALF_HEIGHT]);
317     }
318     canvas.DetachBrush();
319 }
320 
PaintSelectedIndicator(RSCanvas & canvas,const OffsetF & leftCenter,const OffsetF & rightCenter,const LinearVector<float> & itemHalfSizes,bool isOverlong)321 void DotIndicatorModifier::PaintSelectedIndicator(RSCanvas& canvas, const OffsetF& leftCenter,
322     const OffsetF& rightCenter, const LinearVector<float>& itemHalfSizes, bool isOverlong)
323 {
324     RSBrush brush;
325     brush.SetAntiAlias(true);
326     brush.SetColor(ToRSColor(originalSelectColor_));
327     canvas.AttachBrush(brush);
328 
329     auto selectedItemHalfWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH];
330     if (isCustomSize_ && !isOverlong) {
331         selectedItemHalfWidth = itemHalfSizes[SELECTED_ITEM_HALF_WIDTH] * HALF_FLOAT;
332     }
333 
334     float rectLeft = (axis_ == Axis::HORIZONTAL ? leftCenter.GetX() - selectedItemHalfWidth
335                                                 : leftCenter.GetY() - itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT]);
336 
337     float rectTop = (axis_ == Axis::HORIZONTAL ? leftCenter.GetY() - itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT]
338                                                : leftCenter.GetX() - selectedItemHalfWidth);
339     float rectRight = (axis_ == Axis::HORIZONTAL ? rightCenter.GetX() + selectedItemHalfWidth
340                                                  : rightCenter.GetY() + itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT]);
341 
342     float rectBottom = (axis_ == Axis::HORIZONTAL ? rightCenter.GetY() + itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT]
343                                                   : rightCenter.GetX() + selectedItemHalfWidth);
344 
345     float rectSelectedItemWidth = selectedItemHalfWidth * TWO_FLOAT;
346     float rectSelectedItemHeight = itemHalfSizes[SELECTED_ITEM_HALF_HEIGHT] * TWO_FLOAT;
347 
348     if (rectSelectedItemHeight > rectSelectedItemWidth && !isCustomSize_) {
349         canvas.DrawRoundRect(
350             { { rectLeft, rectTop, rectRight, rectBottom }, rectSelectedItemWidth, rectSelectedItemWidth });
351     } else {
352         canvas.DrawRoundRect(
353             { { rectLeft, rectTop, rectRight, rectBottom }, rectSelectedItemHeight, rectSelectedItemHeight });
354     }
355     canvas.DetachBrush();
356 }
357 
PaintMask(DrawingContext & context)358 void DotIndicatorModifier::PaintMask(DrawingContext& context)
359 {
360     RSCanvas& canvas = context.canvas;
361 
362     RSBrush brush;
363     brush.SetAntiAlias(true);
364     canvas.Save();
365 
366     std::vector<RSColorQuad> colors;
367     colors.push_back(0x00000000);
368     colors.push_back(0xff000000);
369     colors.push_back(0xff000000);
370 
371     RSPoint startPt = { offset_.GetX(), offset_.GetY() };
372     RSPoint endPt = { offset_.GetX(), offset_.GetY() };
373     startPt -= axis_ == Axis::HORIZONTAL ? RSPoint(0, (9.0_vp).ConvertToPx()) : RSPoint((9.0_vp).ConvertToPx(), 0);
374     endPt += axis_ == Axis::HORIZONTAL ? RSPoint(0, (15.0_vp).ConvertToPx()) : RSPoint((15.0_vp).ConvertToPx(), 0);
375 
376     std::vector<float> pos = { 0.0f, 0.75f, 1.0f };
377 
378     brush.SetShaderEffect(RSShaderEffect::CreateLinearGradient(startPt, endPt, colors, pos, RSTileMode::CLAMP));
379     canvas.DrawRect({ startPt.GetX(), startPt.GetY(), endPt.GetX(), endPt.GetY() });
380 }
381 
UpdateShrinkPaintProperty(const OffsetF & margin,const LinearVector<float> & normalItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)382 void DotIndicatorModifier::UpdateShrinkPaintProperty(
383     const OffsetF& margin, const LinearVector<float>& normalItemHalfSizes,
384     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
385 {
386     indicatorMargin_->Set(margin);
387     indicatorPadding_->Set(static_cast<float>(paddingSide_.ConvertToPx()));
388 
389     if (longPointLeftAnimEnd_ && longPointRightAnimEnd_) {
390         vectorBlackPointCenterX_->Set(vectorBlackPointCenterX);
391         longPointLeftCenterX_->Set(longPointCenterX.first);
392         longPointRightCenterX_->Set(longPointCenterX.second);
393     }
394 
395     itemHalfSizes_->Set(normalItemHalfSizes);
396     normalToHoverPointDilateRatio_->Set(1.0f);
397     hoverToNormalPointDilateRatio_->Set(1.0f);
398     longPointDilateRatio_->Set(1.0f);
399     backgroundWidthDilateRatio_->Set(1.0f);
400     backgroundHeightDilateRatio_->Set(1.0f);
401 }
402 
UpdateDilatePaintProperty(const LinearVector<float> & hoverItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)403 void DotIndicatorModifier::UpdateDilatePaintProperty(
404     const LinearVector<float>& hoverItemHalfSizes, const LinearVector<float>& vectorBlackPointCenterX,
405     const std::pair<float, float>& longPointCenterX)
406 {
407     indicatorMargin_->Set({ 0, 0 });
408     indicatorPadding_->Set(static_cast<float>(paddingSide_.ConvertToPx()));
409 
410     vectorBlackPointCenterX_->Set(vectorBlackPointCenterX);
411     if (longPointLeftAnimEnd_ && longPointRightAnimEnd_) {
412         longPointLeftCenterX_->Set(longPointCenterX.first);
413         longPointRightCenterX_->Set(longPointCenterX.second);
414     }
415     itemHalfSizes_->Set(hoverItemHalfSizes);
416     backgroundWidthDilateRatio_->Set(1.0f);
417     backgroundHeightDilateRatio_->Set(1.0f);
418 }
419 
UpdateBackgroundColor(const Color & backgroundColor)420 void DotIndicatorModifier::UpdateBackgroundColor(const Color& backgroundColor)
421 {
422     backgroundColor_->Set(LinearColor(backgroundColor));
423 }
424 
UpdateNormalPaintProperty(const OffsetF & margin,const LinearVector<float> & normalItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)425 void DotIndicatorModifier::UpdateNormalPaintProperty(
426     const OffsetF& margin, const LinearVector<float>& normalItemHalfSizes,
427     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
428 {
429     auto swiperTheme = GetSwiperIndicatorTheme();
430     CHECK_NULL_VOID(swiperTheme);
431     auto backgroundColor = indicatorMask_ ?
432         swiperTheme->GetPressedColor() :
433         swiperTheme->GetHoverColor().ChangeOpacity(0);
434     UpdateShrinkPaintProperty(margin, normalItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
435     UpdateBackgroundColor(backgroundColor);
436 }
437 
UpdateHoverPaintProperty(const LinearVector<float> & hoverItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)438 void DotIndicatorModifier::UpdateHoverPaintProperty(
439     const LinearVector<float>& hoverItemHalfSizes,
440     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
441 {
442     auto swiperTheme = GetSwiperIndicatorTheme();
443     CHECK_NULL_VOID(swiperTheme);
444     auto backgroundColor = swiperTheme->GetHoverColor();
445     UpdateDilatePaintProperty(hoverItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
446     UpdateBackgroundColor(backgroundColor);
447 }
448 
UpdatePressPaintProperty(const LinearVector<float> & hoverItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)449 void DotIndicatorModifier::UpdatePressPaintProperty(
450     const LinearVector<float>& hoverItemHalfSizes,
451     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
452 {
453     auto swiperTheme = GetSwiperIndicatorTheme();
454     CHECK_NULL_VOID(swiperTheme);
455     auto backgroundColor = swiperTheme->GetPressedColor();
456     UpdateDilatePaintProperty(hoverItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
457     UpdateBackgroundColor(backgroundColor);
458 }
459 
UpdateNormalToHoverPaintProperty(const LinearVector<float> & hoverItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)460 void DotIndicatorModifier::UpdateNormalToHoverPaintProperty(
461     const LinearVector<float>& hoverItemHalfSizes, const LinearVector<float>& vectorBlackPointCenterX,
462     const std::pair<float, float>& longPointCenterX)
463 {
464     AnimationOption option;
465     option.SetDuration(COMPONENT_DILATE_ANIMATION_DURATION);
466     option.SetCurve(Curves::SHARP);
467     longPointLeftAnimEnd_ = true;
468     longPointRightAnimEnd_ = true;
469     AnimationUtils::Animate(option, [weak = WeakClaim(this), hoverItemHalfSizes, vectorBlackPointCenterX,
470         longPointCenterX]() {
471         auto modifier = weak.Upgrade();
472         CHECK_NULL_VOID(modifier);
473         modifier->UpdateHoverPaintProperty(hoverItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
474     });
475 }
476 
UpdateHoverToNormalPaintProperty(const OffsetF & margin,const LinearVector<float> & normalItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)477 void DotIndicatorModifier::UpdateHoverToNormalPaintProperty(
478     const OffsetF& margin, const LinearVector<float>& normalItemHalfSizes,
479     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
480 {
481     AnimationOption option;
482     option.SetDuration(COMPONENT_SHRINK_ANIMATION_DURATION);
483     option.SetCurve(Curves::SHARP);
484     longPointLeftAnimEnd_ = true;
485     longPointRightAnimEnd_ = true;
486     AnimationUtils::Animate(option, [weak = WeakClaim(this), margin, normalItemHalfSizes, vectorBlackPointCenterX,
487         longPointCenterX]() {
488         auto modifier = weak.Upgrade();
489         CHECK_NULL_VOID(modifier);
490         modifier->UpdateNormalPaintProperty(margin, normalItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
491     });
492 }
493 
UpdateNormalToPressPaintProperty(const LinearVector<float> & hoverItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)494 void DotIndicatorModifier::UpdateNormalToPressPaintProperty(
495     const LinearVector<float>& hoverItemHalfSizes, const LinearVector<float>& vectorBlackPointCenterX,
496     const std::pair<float, float>& longPointCenterX)
497 {
498     AnimationOption option;
499     option.SetDuration(COMPONENT_DILATE_ANIMATION_DURATION);
500     option.SetCurve(Curves::SHARP);
501     longPointLeftAnimEnd_ = true;
502     longPointRightAnimEnd_ = true;
503     AnimationUtils::Animate(option, [weak = WeakClaim(this), hoverItemHalfSizes, vectorBlackPointCenterX,
504         longPointCenterX]() {
505         auto modifier = weak.Upgrade();
506         CHECK_NULL_VOID(modifier);
507         modifier->UpdatePressPaintProperty(hoverItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
508     });
509 }
510 
UpdatePressToNormalPaintProperty(const OffsetF & margin,const LinearVector<float> & normalItemHalfSizes,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)511 void DotIndicatorModifier::UpdatePressToNormalPaintProperty(
512     const OffsetF& margin, const LinearVector<float>& normalItemHalfSizes,
513     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
514 {
515     AnimationOption option;
516     option.SetDuration(COMPONENT_SHRINK_ANIMATION_DURATION);
517     option.SetCurve(Curves::SHARP);
518     AnimationUtils::Animate(option, [weak = WeakClaim(this), margin, normalItemHalfSizes, vectorBlackPointCenterX,
519         longPointCenterX]() {
520         auto modifier = weak.Upgrade();
521         CHECK_NULL_VOID(modifier);
522         modifier->UpdateNormalPaintProperty(margin, normalItemHalfSizes, vectorBlackPointCenterX, longPointCenterX);
523     });
524 }
525 
UpdateHoverAndPressConversionPaintProperty()526 void DotIndicatorModifier::UpdateHoverAndPressConversionPaintProperty()
527 {
528     auto swiperTheme = GetSwiperIndicatorTheme();
529     CHECK_NULL_VOID(swiperTheme);
530     Color backgroundColor = isPressed_ ? swiperTheme->GetPressedColor() : swiperTheme->GetHoverColor();
531     AnimationOption option;
532     option.SetDuration(MOUSE_PRESS_ANIMATION_DURATION);
533     option.SetCurve(Curves::SHARP);
534     AnimationUtils::Animate(option, [weak = WeakClaim(this), backgroundColor]() {
535         auto modifier = weak.Upgrade();
536         CHECK_NULL_VOID(modifier);
537         modifier->UpdateBackgroundColor(backgroundColor);
538     });
539 }
540 
UpdateNormalToHoverPointDilateRatio()541 void DotIndicatorModifier::UpdateNormalToHoverPointDilateRatio()
542 {
543     normalToHoverPointDilateRatio_->Set(1.0f);
544     AnimationOption option;
545     option.SetDuration(POINT_HOVER_ANIMATION_DURATION);
546     option.SetCurve(Curves::SHARP);
547     AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
548         auto modifier = weak.Upgrade();
549         CHECK_NULL_VOID(modifier);
550         modifier->normalToHoverPointDilateRatio_->Set(modifier->scaleIndicator_);
551     });
552 }
553 
UpdateHoverToNormalPointDilateRatio()554 void DotIndicatorModifier::UpdateHoverToNormalPointDilateRatio()
555 {
556     hoverToNormalPointDilateRatio_->Set(normalToHoverPointDilateRatio_->Get());
557     AnimationOption option;
558     option.SetDuration(POINT_HOVER_ANIMATION_DURATION);
559     option.SetCurve(Curves::SHARP);
560     AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
561         auto modifier = weak.Upgrade();
562         CHECK_NULL_VOID(modifier);
563         modifier->hoverToNormalPointDilateRatio_->Set(1.0f);
564     });
565 }
566 
UpdateLongPointDilateRatio()567 void DotIndicatorModifier::UpdateLongPointDilateRatio()
568 {
569     AnimationOption option;
570     option.SetDuration(POINT_HOVER_ANIMATION_DURATION);
571     option.SetCurve(Curves::SHARP);
572     if (longPointIsHover_) {
573         AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
574             auto modifier = weak.Upgrade();
575             CHECK_NULL_VOID(modifier);
576             modifier->longPointDilateRatio_->Set(modifier->scaleIndicator_);
577         });
578     } else {
579         AnimationUtils::Animate(option, [weak = WeakClaim(this)]() {
580             auto modifier = weak.Upgrade();
581             CHECK_NULL_VOID(modifier);
582             modifier->longPointDilateRatio_->Set(1.0f);
583         });
584     }
585 }
586 
UpdateAllPointCenterXAnimation(GestureState gestureState,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX)587 void DotIndicatorModifier::UpdateAllPointCenterXAnimation(GestureState gestureState,
588     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX)
589 {
590     AnimationOption blackPointOption;
591     blackPointOption.SetDuration(BLACK_POINT_DURATION);
592     blackPointOption.SetCurve(AceType::MakeRefPtr<CubicCurve>(BLACK_POINT_CENTER_BEZIER_CURVE_VELOCITY,
593         CENTER_BEZIER_CURVE_MASS, CENTER_BEZIER_CURVE_STIFFNESS, CENTER_BEZIER_CURVE_DAMPING));
594     AnimationUtils::Animate(blackPointOption, [weak = WeakClaim(this), vectorBlackPointCenterX]() {
595         auto modifier = weak.Upgrade();
596         CHECK_NULL_VOID(modifier);
597         modifier->vectorBlackPointCenterX_->Set(vectorBlackPointCenterX);
598     });
599 
600     // normal page turning
601     AnimationOption optionHead;
602     RefPtr<Curve> curve = headCurve_;
603     optionHead.SetCurve(curve);
604     optionHead.SetDuration(animationDuration_);
605 
606     AnimationOption optionTail;
607     optionTail.SetCurve(GetTailCurve());
608     optionTail.SetDuration(animationDuration_);
609     AnimationOption optionLeft = optionTail;
610     AnimationOption optionRight = optionHead;
611 
612     if (gestureState == GestureState::GESTURE_STATE_RELEASE_LEFT) {
613         optionLeft = optionHead;
614         optionRight = optionTail;
615     }
616 
617     if (longPointLeftAnimEnd_ && longPointRightAnimEnd_) {
618         longPointLeftAnimEnd_ = false;
619         longPointRightAnimEnd_ = false;
620         auto weak = WeakClaim(this);
621         AnimationUtils::StartAnimation(optionLeft, [weak, longPointCenterX]() {
622                 auto modifier = weak.Upgrade();
623                 CHECK_NULL_VOID(modifier);
624                 modifier->longPointLeftCenterX_->Set(longPointCenterX.first);
625             }, [weak]() {
626                 auto modifier = weak.Upgrade();
627                 CHECK_NULL_VOID(modifier);
628                 modifier->longPointLeftAnimEnd_ = true;
629             });
630 
631         AnimationUtils::StartAnimation(optionRight, [weak, longPointCenterX]() {
632                 auto modifier = weak.Upgrade();
633                 CHECK_NULL_VOID(modifier);
634                 modifier->longPointRightCenterX_->Set(longPointCenterX.second);
635             }, [weak]() {
636                 auto modifier = weak.Upgrade();
637                 CHECK_NULL_VOID(modifier);
638                 modifier->longPointRightAnimEnd_ = true;
639             });
640     }
641 }
642 
UpdateTouchBottomAnimation(TouchBottomType touchBottomType,const LinearVector<float> & vectorBlackPointCenterX,const std::pair<float,float> & longPointCenterX,float touchBottomRate)643 void DotIndicatorModifier::UpdateTouchBottomAnimation(TouchBottomType touchBottomType,
644     const LinearVector<float>& vectorBlackPointCenterX, const std::pair<float, float>& longPointCenterX,
645     float touchBottomRate)
646 {
647     AnimationOption option;
648     option.SetDuration(POINT_HOVER_ANIMATION_DURATION);
649     option.SetCurve(AceType::MakeRefPtr<CubicCurve>(TOUCH_BOTTOM_CURVE_VELOCITY, TOUCH_BOTTOM_CURVE_MASS,
650         TOUCH_BOTTOM_CURVE_STIFFNESS, TOUCH_BOTTOM_CURVE_DAMPING));
651 
652     auto backgroundWidthDilateRatio = 1.0f;
653     auto backgroundHeightDilateRatio = 1.0f;
654 
655     if (touchBottomType != TouchBottomType::NONE) {
656         backgroundWidthDilateRatio = TOUCH_BOTTOM_BACKGROUND_WIDTH_MULTIPLE -
657                                      TOUCH_BOTTOM_DOT_WIDTH_MULTIPLE * vectorBlackPointCenterX_->Get().size();
658         backgroundHeightDilateRatio = TOUCH_BOTTOM_BACKGROUND_HEIGHT_MULTIPLE;
659         backgroundWidthDilateRatio = (backgroundWidthDilateRatio - 1.0f) * touchBottomRate + 1.0f;
660         backgroundHeightDilateRatio = (backgroundHeightDilateRatio - 1.0f) * touchBottomRate + 1.0f;
661     }
662     touchBottomType_ = touchBottomType;
663     AnimationUtils::Animate(option, [weak = WeakClaim(this), backgroundWidthDilateRatio, backgroundHeightDilateRatio,
664                                         vectorBlackPointCenterX, longPointCenterX]() {
665         auto modifier = weak.Upgrade();
666         CHECK_NULL_VOID(modifier);
667         modifier->backgroundWidthDilateRatio_->Set(backgroundWidthDilateRatio);
668         modifier->backgroundHeightDilateRatio_->Set(backgroundHeightDilateRatio);
669         modifier->vectorBlackPointCenterX_->Set(vectorBlackPointCenterX);
670         if (modifier->longPointLeftAnimEnd_) {
671             modifier->longPointLeftCenterX_->Set(longPointCenterX.first);
672         }
673         if (modifier->longPointRightAnimEnd_) {
674             modifier->longPointRightCenterX_->Set(longPointCenterX.second);
675         }
676     });
677 }
678 
PlayBlackPointsAnimation(const LinearVector<float> & vectorBlackPointCenterX)679 void DotIndicatorModifier::PlayBlackPointsAnimation(const LinearVector<float>& vectorBlackPointCenterX)
680 {
681     auto curve = AceType::MakeRefPtr<CubicCurve>(BLACK_POINT_CENTER_BEZIER_CURVE_VELOCITY, CENTER_BEZIER_CURVE_MASS,
682         CENTER_BEZIER_CURVE_STIFFNESS, CENTER_BEZIER_CURVE_DAMPING);
683     AnimationOption option;
684     option.SetCurve(curve);
685     option.SetDuration(animationDuration_);
686     AnimationUtils::StartAnimation(option, [weak = WeakClaim(this), vectorBlackPointCenterX]() {
687         auto modifier = weak.Upgrade();
688         CHECK_NULL_VOID(modifier);
689         modifier->vectorBlackPointCenterX_->Set(vectorBlackPointCenterX);
690     });
691 }
692 
PlayOpacityAnimation()693 void DotIndicatorModifier::PlayOpacityAnimation()
694 {
695     AnimationOption optionOpacity;
696     // x0:0.33, y0:0, x1:0.67, y1:1
697     optionOpacity.SetCurve(AceType::MakeRefPtr<CubicCurve>(0.33, 0, 0.67, 1));
698     optionOpacity.SetDuration(GetLoopOpacityDuration());
699     isSelectedColorAnimEnd_ = false;
700     isTouchBottomLoop_ = true;
701     selectedColor_->Set(LinearColor(selectedColor_->Get().BlendOpacity(0.0f)));
702     auto weak = WeakClaim(this);
703     AnimationUtils::StartAnimation(optionOpacity, [weak]() {
704             auto modifier = weak.Upgrade();
705             CHECK_NULL_VOID(modifier);
706             auto color = modifier->selectedColor_->Get();
707             auto targetColor =
708                 LinearColor(Color::FromARGB(TARGET_ALPHA, color.GetRed(), color.GetGreen(), color.GetBlue()));
709             modifier->selectedColor_->Set(targetColor);
710             modifier->touchBottomPointColor_->Set(LinearColor(modifier->touchBottomPointColor_->Get().BlendOpacity(0)));
711         }, [weak]() {
712             auto modifier = weak.Upgrade();
713             CHECK_NULL_VOID(modifier);
714             modifier->touchBottomPointColor_->Set(LinearColor(modifier->unselectedColor_->Get()));
715             modifier->isTouchBottomLoop_ = false;
716             modifier->isSelectedColorAnimEnd_ = true;
717         });
718 }
719 
GetLoopTranslateDuration() const720 int32_t DotIndicatorModifier::GetLoopTranslateDuration() const
721 {
722     if (InstanceOf<InterpolatingSpring>(headCurve_)) {
723         return DEFAULT_TOUCH_BOTTOM_ANIMATION_DURATION;
724     }
725 
726     return static_cast<int32_t>(static_cast<float>(animationDuration_) * LOOP_TRANSLATE_DURATION_PERCENT);
727 }
728 
GetLoopOpacityDuration() const729 int32_t DotIndicatorModifier::GetLoopOpacityDuration() const
730 {
731     if (InstanceOf<InterpolatingSpring>(headCurve_)) {
732         return DEFAULT_OPACITY_ANIMATION_DURATION;
733     }
734 
735     return static_cast<int32_t>(static_cast<float>(animationDuration_) * LOOP_OPACITY_DURATION_PERCENT);
736 }
737 
PlayTouchBottomAnimation(const std::vector<std::pair<float,float>> & longPointCenterX,TouchBottomTypeLoop touchBottomTypeLoop,const LinearVector<float> & vectorBlackPointCenterX)738 void DotIndicatorModifier::PlayTouchBottomAnimation(const std::vector<std::pair<float, float>>& longPointCenterX,
739     TouchBottomTypeLoop touchBottomTypeLoop, const LinearVector<float>& vectorBlackPointCenterX)
740 {
741     if (vectorBlackPointCenterX.empty()) {
742         return;
743     }
744 
745     AnimationOption optionBottom;
746     // x0:0.33, y0:0, x1:0.67, y1:1
747     optionBottom.SetCurve(AceType::MakeRefPtr<CubicCurve>(0.33, 0, 0.67, 1));
748     optionBottom.SetDuration(GetLoopTranslateDuration());
749 
750     auto weak = WeakClaim(this);
751     FinishCallback bottomFinishCallback = [weak, optionBottom, longPointCenterX, vectorBlackPointCenterX,
752                                               touchBottomTypeLoop]() {
753         auto modifier = weak.Upgrade();
754         CHECK_NULL_VOID(modifier);
755         modifier->animationState_ = TouchBottomAnimationStage::STAGE_NONE;
756         if (!(modifier->ifNeedFinishCallback_)) {
757             return;
758         }
759         modifier->animationState_ = TouchBottomAnimationStage::STAGE_EXPAND_TO_LONG_POINT;
760         modifier->PlayOpacityAnimation();
761         if (touchBottomTypeLoop == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_LEFT) {
762             modifier->longPointLeftCenterX_->Set(vectorBlackPointCenterX[vectorBlackPointCenterX.size() - 1]);
763             modifier->longPointRightCenterX_->Set(vectorBlackPointCenterX[vectorBlackPointCenterX.size() - 1]);
764         } else if (touchBottomTypeLoop == TouchBottomTypeLoop::TOUCH_BOTTOM_TYPE_LOOP_RIGHT) {
765             modifier->longPointLeftCenterX_->Set(vectorBlackPointCenterX[0]);
766             modifier->longPointRightCenterX_->Set(vectorBlackPointCenterX[0]);
767         }
768 
769         AnimationUtils::StartAnimation(optionBottom, [weak, longPointCenterX]() {
770             auto modifier = weak.Upgrade();
771             CHECK_NULL_VOID(modifier);
772             modifier->longPointRightCenterX_->Set(longPointCenterX[1].second);
773             if (modifier->isCustomSize_) {
774                 modifier->longPointLeftCenterX_->Set(longPointCenterX[1].second);
775             } else {
776                 modifier->longPointLeftCenterX_->Set(longPointCenterX[1].first);
777             }
778         }, [weak]() {
779             auto modifier = weak.Upgrade();
780             CHECK_NULL_VOID(modifier);
781             modifier->longPointLeftAnimEnd_ = true;
782             modifier->longPointRightAnimEnd_ = true;
783             modifier->isBottomAnimationFinished_ = true;
784             modifier->animationState_ = TouchBottomAnimationStage::STAGE_NONE;
785         });
786     };
787     if (longPointLeftAnimEnd_ && longPointRightAnimEnd_) {
788         longPointLeftAnimEnd_ = false;
789         longPointRightAnimEnd_ = false;
790         ifNeedFinishCallback_ = true;
791         isBottomAnimationFinished_ = false;
792         animationState_ = TouchBottomAnimationStage::STAGE_SHRINKT_TO_BLACK_POINT;
793         touchBottomPointColor_->Set(LinearColor(selectedColor_->Get()));
794         AnimationUtils::StartAnimation(optionBottom, [weak, longPointCenterX]() {
795             auto modifier = weak.Upgrade();
796             CHECK_NULL_VOID(modifier);
797             modifier->longPointLeftCenterX_->Set(longPointCenterX[0].first);
798             modifier->longPointRightCenterX_->Set(longPointCenterX[0].second);
799             modifier->bottomCenterX_ = longPointCenterX[1];
800         }, bottomFinishCallback);
801     }
802 }
803 
CalculateMinimumAmplitudeRatio(const std::vector<std::pair<float,float>> & longPointCenterX,GestureState gestureState) const804 float DotIndicatorModifier::CalculateMinimumAmplitudeRatio(
805     const std::vector<std::pair<float, float>>& longPointCenterX, GestureState gestureState) const
806 {
807     auto minimumAmplitudeRatio =
808         NearEqual(longPointCenterX[0].first, longPointLeftCenterX_->Get())
809             ? InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO
810             : DEFAULT_MINIMUM_AMPLITUDE_PX / std::abs(longPointCenterX[0].first - longPointLeftCenterX_->Get());
811     if (gestureState == GestureState::GESTURE_STATE_RELEASE_LEFT) {
812         minimumAmplitudeRatio =
813             NearEqual(longPointCenterX[0].second, longPointRightCenterX_->Get())
814                 ? InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO
815                 : DEFAULT_MINIMUM_AMPLITUDE_PX / std::abs(longPointCenterX[0].second - longPointRightCenterX_->Get());
816     }
817     return std::max(minimumAmplitudeRatio, InterpolatingSpring::DEFAULT_INTERPOLATING_SPRING_AMPLITUDE_RATIO);
818 }
819 
GetTailCurve()820 RefPtr<InterpolatingSpring> DotIndicatorModifier::GetTailCurve()
821 {
822     auto step = std::abs(currentIndex_ - currentIndexActual_);
823     if (step == LONG_POINT_STEP_TWO) {
824         return LONG_POINT_STEP_TWO_CURVE;
825     }
826 
827     if (step == LONG_POINT_STEP_THREE) {
828         return LONG_POINT_STEP_THREE_CURVE;
829     }
830 
831     if (step == LONG_POINT_STEP_FOUR) {
832         return LONG_POINT_STEP_FOUR_CURVE;
833     }
834 
835     if (step > LONG_POINT_STEP_FOUR) {
836         return LONG_POINT_STEP_FIVE_CURVE;
837     }
838 
839     return LONG_POINT_DEFAULT_CURVE;
840 }
841 
CreateTailOption(const std::vector<std::pair<float,float>> & longPointCenterX,GestureState gestureState,bool isNormal)842 AnimationOption DotIndicatorModifier::CreateTailOption(
843     const std::vector<std::pair<float, float>>& longPointCenterX, GestureState gestureState, bool isNormal)
844 {
845     AnimationOption optionTail;
846     optionTail.SetDuration(animationDuration_);
847 
848     if (userSetSwiperCurve_) {
849         optionTail.SetCurve(headCurve_);
850         return optionTail;
851     }
852 
853     auto interpolatingSpring = GetTailCurve();
854     if (isNormal) {
855         interpolatingSpring->UpdateMinimumAmplitudeRatio(
856             CalculateMinimumAmplitudeRatio(longPointCenterX, gestureState));
857     }
858     optionTail.SetCurve(interpolatingSpring);
859     return optionTail;
860 }
861 
PlayLongPointAnimation(const std::vector<std::pair<float,float>> & longPointCenterX,GestureState gestureState,TouchBottomTypeLoop touchBottomTypeLoop,const LinearVector<float> & vectorBlackPointCenterX,bool isNormal)862 void DotIndicatorModifier::PlayLongPointAnimation(const std::vector<std::pair<float, float>>& longPointCenterX,
863     GestureState gestureState, TouchBottomTypeLoop touchBottomTypeLoop,
864     const LinearVector<float>& vectorBlackPointCenterX, bool isNormal)
865 {
866     if (longPointCenterX.empty()) {
867         return;
868     }
869     // touch bottom
870     if (longPointCenterX.size() > 1) {
871         PlayTouchBottomAnimation(longPointCenterX, touchBottomTypeLoop, vectorBlackPointCenterX);
872         return;
873     }
874     // normal page turning
875     AnimationOption optionHead;
876     RefPtr<Curve> curve = headCurve_;
877     optionHead.SetCurve(curve);
878     optionHead.SetDuration(animationDuration_);
879 
880     AnimationOption optionTail = CreateTailOption(longPointCenterX, gestureState, isNormal);
881     AnimationOption optionLeft = optionTail;
882     AnimationOption optionRight = optionHead;
883 
884     if (gestureState == GestureState::GESTURE_STATE_RELEASE_LEFT) {
885         optionLeft = optionHead;
886         optionRight = optionTail;
887     }
888 
889     if (longPointLeftAnimEnd_ && longPointRightAnimEnd_) {
890         longPointLeftAnimEnd_ = false;
891         longPointRightAnimEnd_ = false;
892         auto weak = WeakClaim(this);
893         AnimationUtils::StartAnimation(optionLeft, [weak, longPointCenterX]() {
894                 auto modifier = weak.Upgrade();
895                 CHECK_NULL_VOID(modifier);
896                 modifier->longPointLeftCenterX_->Set(longPointCenterX[0].first);
897             }, [weak]() {
898                 auto modifier = weak.Upgrade();
899                 CHECK_NULL_VOID(modifier);
900                 modifier->longPointLeftAnimEnd_ = true;
901             });
902 
903         AnimationUtils::StartAnimation(optionRight, [weak, longPointCenterX]() {
904                 auto modifier = weak.Upgrade();
905                 CHECK_NULL_VOID(modifier);
906                 modifier->longPointRightCenterX_->Set(longPointCenterX[0].second);
907             }, [weak]() {
908                 auto modifier = weak.Upgrade();
909                 CHECK_NULL_VOID(modifier);
910                 modifier->longPointRightAnimEnd_ = true;
911             });
912     }
913 }
914 
PlayIndicatorAnimation(const LinearVector<float> & vectorBlackPointCenterX,const std::vector<std::pair<float,float>> & longPointCenterX,GestureState gestureState,TouchBottomTypeLoop touchBottomTypeLoop)915 void DotIndicatorModifier::PlayIndicatorAnimation(const LinearVector<float>& vectorBlackPointCenterX,
916     const std::vector<std::pair<float, float>>& longPointCenterX, GestureState gestureState,
917     TouchBottomTypeLoop touchBottomTypeLoop)
918 {
919     StopAnimation();
920     isTouchBottomLoop_ = false;
921     animationState_ = TouchBottomAnimationStage::STAGE_NONE;
922     PlayBlackPointsAnimation(vectorBlackPointCenterX);
923     PlayLongPointAnimation(longPointCenterX, gestureState, touchBottomTypeLoop, vectorBlackPointCenterX);
924 }
925 
FinishAnimationToTargetImmediately(std::pair<float,float> centerX)926 void DotIndicatorModifier::FinishAnimationToTargetImmediately(std::pair<float, float> centerX)
927 {
928     AnimationOption option;
929     option.SetDuration(0);
930     option.SetCurve(Curves::LINEAR);
931     AnimationUtils::StartAnimation(option, [weak = WeakClaim(this), centerX]() {
932         auto modifier = weak.Upgrade();
933         CHECK_NULL_VOID(modifier);
934         modifier->isBottomAnimationFinished_ = true;
935         modifier->ifNeedFinishCallback_ = false;
936         modifier->longPointRightCenterX_->Set(centerX.second);
937         if (modifier->isCustomSize_) {
938             modifier->longPointLeftCenterX_->Set(centerX.second);
939         } else {
940             modifier->longPointLeftCenterX_->Set(centerX.first);
941         }
942     });
943 }
944 
StopAnimation(bool ifImmediately)945 void DotIndicatorModifier::StopAnimation(bool ifImmediately)
946 {
947     if (ifImmediately) {
948         AnimationOption option;
949         option.SetDuration(0);
950         option.SetCurve(Curves::LINEAR);
951         AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
952             auto modifier = weak.Upgrade();
953             CHECK_NULL_VOID(modifier);
954             modifier->ifNeedFinishCallback_ = false;
955             modifier->longPointLeftCenterX_->Set(modifier->longPointLeftCenterX_->Get());
956             modifier->longPointRightCenterX_->Set(modifier->longPointRightCenterX_->Get());
957         });
958     }
959     AnimationOption option;
960     option.SetDuration(0);
961     option.SetCurve(Curves::LINEAR);
962     AnimationUtils::StartAnimation(option, [weak = WeakClaim(this)]() {
963         auto modifier = weak.Upgrade();
964         CHECK_NULL_VOID(modifier);
965         modifier->vectorBlackPointCenterX_->Set(modifier->vectorBlackPointCenterX_->Get());
966     });
967     longPointLeftAnimEnd_ = true;
968     longPointRightAnimEnd_ = true;
969     ifNeedFinishCallback_ = false;
970 }
971 } // namespace OHOS::Ace::NG
972