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/patternlock/patternlock_modifier.h"
17
18 #include <algorithm>
19 #include <string>
20 #include <vector>
21
22 #include "base/geometry/dimension.h"
23 #include "base/geometry/ng/offset_t.h"
24 #include "base/geometry/ng/size_t.h"
25 #include "base/log/log_wrapper.h"
26 #include "base/memory/ace_type.h"
27 #include "base/utils/utils.h"
28 #include "core/components/common/properties/color.h"
29 #include "core/components_ng/base/modifier.h"
30 #include "core/components_ng/pattern/patternlock/patternlock_paint_property.h"
31 #include "core/components_ng/render/drawing.h"
32 #include "core/components_ng/render/drawing_prop_convertor.h"
33
34 namespace OHOS::Ace::NG {
35 namespace {
36 constexpr int32_t PATTERN_LOCK_COL_COUNT = 3;
37 constexpr int32_t PATTERN_LOCK_POINT_COUNT = 9;
38 constexpr int32_t RADIUS_TO_DIAMETER = 2;
39 constexpr float FLASH_POINT_OPACITY = 0.5f;
40 constexpr int32_t ACTIVE_RADIUS_ANIMATION_DURATION = 200;
41 constexpr int32_t LIGHT_RING_RADIUS_ANIMATION_DURATION = 500;
42 constexpr int32_t LIGHT_RING_ALPHAF_ANIMATION_DURATION_FIRST = 200;
43 constexpr int32_t LIGHT_RING_ALPHAF_ANIMATION_DURATION_SECOND = 300;
44 constexpr int32_t CONNECT_ANIMATION_DURATION_FIRST = 100;
45 constexpr int32_t WRONG_ANIMATION_DURATION_DIMMING = 150;
46 constexpr int32_t WRONG_ANIMATION_DURATION_BRIGHTENING = 200;
47 constexpr int32_t WRONG_ANIMATION_DURATION_FLASH_ONCE =
48 WRONG_ANIMATION_DURATION_DIMMING + WRONG_ANIMATION_DURATION_BRIGHTENING;
49 constexpr int32_t WRONG_ANIMATION_DURATION_FLASH_TWICE =
50 WRONG_ANIMATION_DURATION_FLASH_ONCE + WRONG_ANIMATION_DURATION_FLASH_ONCE;
51 constexpr float BACKGROUND_RADIUS_SPRING_RESPONSE = 0.347f;
52 constexpr float BACKGROUND_RADIUS_SPRING_DAMPING = 0.55f;
53 constexpr Dimension LIGHT_RING_LINE_WIDTH = 2.5_vp;
54 constexpr Dimension LIGHT_RING_MASK_RADIUS = 10.0_vp;
55 constexpr float LIGHT_RING_ALPHAF_START = 0.0f;
56 constexpr float LIGHT_RING_ALPHAF_END = 0.5f;
57 constexpr float CONNECTED_LINE_SPRING_RESPONSE = 0.22f;
58 constexpr float CONNECTED_LINE_SPRING_DAMPING = 0.88f;
59 constexpr float CANCELED_LINE_SPRING_RESPONSE = 0.22f;
60 constexpr float CANCELED_LINE_SPRING_DAMPING = 0.88f;
61 constexpr int32_t ANIMATABLE_POINT_COUNT = 2;
62 constexpr float DIAMETER_TO_RADIUS = 0.5f;
63 constexpr float GRADUAL_CHANGE_POINT = 0.5;
64 constexpr int32_t MAX_ALPHA = 255;
65 } // namespace
66
PatternLockCell(int32_t column,int32_t row)67 PatternLockCell::PatternLockCell(int32_t column, int32_t row)
68 {
69 column_ = column;
70 row_ = row;
71 code_ = PATTERN_LOCK_COL_COUNT * (row - 1) + (column - 1);
72 }
73
CreateProperties()74 void PatternLockModifier::CreateProperties()
75 {
76 sideLength_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
77 circleRadius_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
78 regularColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
79 selectedColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
80 activeColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
81 hoverColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
82 wrongColor_ = AceType::MakeRefPtr<PropertyColor>(Color::RED);
83 correctColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLUE);
84 pathColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::BLUE));
85 pointAnimateColor_ = AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor(Color::BLACK));
86 pathStrokeWidth_ = AceType::MakeRefPtr<PropertyFloat>(0.0f);
87 offset_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
88 cellCenter_ = AceType::MakeRefPtr<PropertyOffsetF>(OffsetF());
89 isMoveEventValid_ = AceType::MakeRefPtr<PropertyBool>(false);
90 isHover_ = AceType::MakeRefPtr<PropertyBool>(false);
91 hoverIndex_ = AceType::MakeRefPtr<PropertyInt>(-1);
92 connectedLineTailPoint_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
93 canceledLineTailPoint_ = AceType::MakeRefPtr<AnimatablePropertyOffsetF>(OffsetF());
94 }
95
AttachProperties()96 void PatternLockModifier::AttachProperties()
97 {
98 AttachProperty(sideLength_);
99 AttachProperty(circleRadius_);
100 AttachProperty(regularColor_);
101 AttachProperty(selectedColor_);
102 AttachProperty(activeColor_);
103 AttachProperty(hoverColor_);
104 AttachProperty(wrongColor_);
105 AttachProperty(correctColor_);
106 AttachProperty(pathColor_);
107 AttachProperty(pointAnimateColor_);
108 AttachProperty(pathStrokeWidth_);
109 AttachProperty(cellCenter_);
110 AttachProperty(offset_);
111 AttachProperty(isMoveEventValid_);
112 AttachProperty(isHover_);
113 AttachProperty(hoverIndex_);
114 AttachProperty(connectedLineTailPoint_);
115 AttachProperty(canceledLineTailPoint_);
116 }
117
PatternLockModifier()118 PatternLockModifier::PatternLockModifier()
119 {
120 CreateProperties();
121 AttachProperties();
122 for (size_t count = 0; count < PATTERN_LOCK_POINT_COUNT; count++) {
123 auto backgroundRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
124 AttachProperty(backgroundRadius);
125 backgroundCircleRadius_.emplace_back(backgroundRadius);
126
127 auto activeRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
128 AttachProperty(activeRadius);
129 activeCircleRadius_.emplace_back(activeRadius);
130
131 auto lightRingRadius = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
132 AttachProperty(lightRingRadius);
133 lightRingRadius_.emplace_back(lightRingRadius);
134
135 auto lightRingAlphaF = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f);
136 AttachProperty(lightRingAlphaF);
137 lightRingAlphaF_.emplace_back(lightRingAlphaF);
138 }
139 }
140
onDraw(DrawingContext & context)141 void PatternLockModifier::onDraw(DrawingContext& context)
142 {
143 auto pipeline = PipelineBase::GetCurrentContext();
144 CHECK_NULL_VOID(pipeline);
145 if (pipeline->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_TEN)) {
146 DrawForApiNine(context);
147 return;
148 }
149 auto& canvas = context.canvas;
150 PaintLockLine(canvas, offset_->Get());
151 canvas.Save();
152 for (int i = 0; i < PATTERN_LOCK_COL_COUNT; i++) {
153 for (int j = 0; j < PATTERN_LOCK_COL_COUNT; j++) {
154 PaintLockCircle(canvas, offset_->Get(), i + 1, j + 1);
155 }
156 }
157 canvas.Restore();
158 }
159
DrawForApiNine(DrawingContext & context)160 void PatternLockModifier::DrawForApiNine(DrawingContext& context)
161 {
162 auto& canvas = context.canvas;
163 PaintLockLineForApiNine(canvas, offset_->Get());
164 canvas.Save();
165 for (int i = 0; i < PATTERN_LOCK_COL_COUNT; i++) {
166 for (int j = 0; j < PATTERN_LOCK_COL_COUNT; j++) {
167 PaintLockCircleForApiNine(canvas, offset_->Get(), i + 1, j + 1);
168 }
169 }
170 canvas.Restore();
171 }
172
PaintLockLineForApiNine(RSCanvas & canvas,const OffsetF & offset)173 void PatternLockModifier::PaintLockLineForApiNine(RSCanvas& canvas, const OffsetF& offset)
174 {
175 size_t count = choosePoint_.size();
176 if (count == 0) {
177 return;
178 }
179
180 float sideLength = sideLength_->Get();
181 float pathStrokeWidth = pathStrokeWidth_->Get();
182 if (LessOrEqual(pathStrokeWidth, 0.0)) {
183 return;
184 }
185 float handleStrokeWidth = std::min(pathStrokeWidth, sideLength / PATTERN_LOCK_COL_COUNT);
186 pathStrokeWidth = std::max(handleStrokeWidth, 0.0f);
187
188 auto pathColor = pathColor_->Get();
189 auto cellCenter = cellCenter_->Get();
190 RSPen pen;
191 pen.SetAntiAlias(true);
192 pen.SetColor(ToRSColor(pathColor));
193 pen.SetWidth(pathStrokeWidth);
194 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
195
196 Color pathColorAlpha255 = pathColor.ToColor().ChangeAlpha(MAX_ALPHA);
197 pen.SetColor(pathColorAlpha255.GetValue());
198 canvas.AttachPen(pen);
199 for (size_t i = 0; i < count - 1; i++) {
200 OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[i].GetColumn(), choosePoint_[i].GetRow());
201 OffsetF pointEnd = GetCircleCenterByXY(offset, choosePoint_[i + 1].GetColumn(), choosePoint_[i + 1].GetRow());
202 canvas.DrawLine(RSPoint(pointBegin.GetX(), pointBegin.GetY()), RSPoint(pointEnd.GetX(), pointEnd.GetY()));
203 }
204 if (isMoveEventValid_->Get()) {
205 OffsetF pointBegin =
206 GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
207 float x1 = pointBegin.GetX();
208 float y1 = pointBegin.GetY();
209 float x2 = cellCenter.GetX();
210 float y2 = cellCenter.GetY();
211 x2 = x2 > offset.GetX() + sideLength ? offset.GetX() + sideLength : x2;
212 x2 = x2 < offset.GetX() ? offset.GetX() : x2;
213 y2 = y2 > offset.GetY() + sideLength ? offset.GetY() + sideLength : y2;
214 y2 = y2 < offset.GetY() ? offset.GetY() : y2;
215
216 std::vector<RSColorQuad> colors = { pathColorAlpha255.GetValue(), pathColorAlpha255.GetValue(),
217 pathColorAlpha255.ChangeOpacity(0.0).GetValue() };
218 std::vector<RSScalar> pos = { 0.0, GRADUAL_CHANGE_POINT, 1.0 };
219 auto shader = pen.GetShaderEffect();
220 shader->CreateLinearGradient(RSPoint(x1, y1), RSPoint(x2, y2), colors, pos, RSTileMode::CLAMP);
221 pen.SetShaderEffect(shader);
222 canvas.DrawLine(RSPoint(x1, y1), RSPoint(x2, y2));
223 }
224 canvas.DetachPen();
225 canvas.Restore();
226 }
227
PaintLockCircleForApiNine(RSCanvas & canvas,const OffsetF & offset,int32_t x,int32_t y)228 void PatternLockModifier::PaintLockCircleForApiNine(RSCanvas& canvas, const OffsetF& offset, int32_t x, int32_t y)
229 {
230 auto activeColor = activeColor_->Get();
231 auto regularColor = regularColor_->Get();
232 auto selectedColor = selectedColor_->Get();
233 auto sideLength = sideLength_->Get();
234 auto circleRadius = circleRadius_->Get();
235
236 RSBrush brush;
237 brush.SetAntiAlias(true);
238 brush.SetColor(ToRSColor(regularColor));
239 OffsetF cellcenter = GetCircleCenterByXY(offset, x, y);
240 OffsetF firstCellcenter = GetCircleCenterByXY(offset, 1, 1);
241 float offsetX = cellcenter.GetX();
242 float offsetY = cellcenter.GetY();
243 const int32_t radiusCount = RADIUS_TO_DIAMETER * PATTERN_LOCK_COL_COUNT;
244 float handleCircleRadius = std::min(circleRadius, sideLength / scaleBackgroundCircleRadius_ / radiusCount);
245 circleRadius = std::max(handleCircleRadius, 0.0f);
246 if (CheckChoosePoint(x, y)) {
247 const int32_t lastIndexFir = 1;
248 if (CheckChoosePointIsLastIndex(x, y, lastIndexFir)) {
249 if (isMoveEventValid_->Get()) {
250 brush.SetColor(ToRSColor(activeColor));
251 canvas.AttachBrush(brush);
252 auto radius = circleRadius * scaleBackgroundCircleRadius_;
253 canvas.DrawCircle(
254 RSPoint(offsetX, offsetY), std::min(static_cast<float>(radius), firstCellcenter.GetX()));
255 } else {
256 brush.SetColor(ToRSColor(selectedColor));
257 canvas.AttachBrush(brush);
258 canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius * scaleActiveCircleRadius_);
259 }
260 } else {
261 brush.SetColor(ToRSColor(selectedColor));
262 canvas.AttachBrush(brush);
263 canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius * scaleActiveCircleRadius_);
264 }
265 } else {
266 canvas.AttachBrush(brush);
267 canvas.DrawCircle(RSPoint(offsetX, offsetY), circleRadius);
268 }
269 canvas.DetachBrush();
270 }
271
PaintLockLine(RSCanvas & canvas,const OffsetF & offset)272 void PatternLockModifier::PaintLockLine(RSCanvas& canvas, const OffsetF& offset)
273 {
274 size_t count = choosePoint_.size();
275 if (count < 1) {
276 return;
277 }
278
279 float sideLength = sideLength_->Get();
280 float pathStrokeWidth = pathStrokeWidth_->Get();
281 if (LessOrEqual(pathStrokeWidth, 0.0)) {
282 return;
283 }
284 float handleStrokeWidth = std::min(pathStrokeWidth, sideLength / PATTERN_LOCK_COL_COUNT);
285 pathStrokeWidth = std::max(handleStrokeWidth, 0.0f);
286
287 auto pathColor = pathColor_->Get();
288 RSPen pen;
289 pen.SetAntiAlias(true);
290 pen.SetWidth(pathStrokeWidth);
291 pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
292
293 pen.SetColor(pathColor.GetValue());
294 canvas.Save();
295 SetCircleClip(canvas);
296 canvas.AttachPen(pen);
297 RSPath path;
298 if (count > ANIMATABLE_POINT_COUNT) {
299 for (size_t i = 0; i < count - ANIMATABLE_POINT_COUNT; i++) {
300 OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[i].GetColumn(), choosePoint_[i].GetRow());
301 OffsetF pointEnd =
302 GetCircleCenterByXY(offset, choosePoint_[i + 1].GetColumn(), choosePoint_[i + 1].GetRow());
303 path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
304 path.LineTo(pointEnd.GetX(), pointEnd.GetY());
305 }
306 }
307 AddConnectedLineToPath(path, offset);
308 if (isMoveEventValid_->Get()) {
309 OffsetF pointBegin =
310 GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
311 OffsetF pointEnd = GetPointEndByCellCenter();
312 if (pointEnd != pointBegin) {
313 path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
314 path.LineTo(pointEnd.GetX(), pointEnd.GetY());
315 }
316 }
317 AddCanceledLineToPath(path, offset);
318 canvas.DrawPath(path);
319 canvas.DetachPen();
320 canvas.Restore();
321 }
322
AddConnectedLineToPath(RSPath & path,const OffsetF & offset)323 void PatternLockModifier::AddConnectedLineToPath(RSPath& path, const OffsetF& offset)
324 {
325 size_t count = choosePoint_.size();
326 if (count < ANIMATABLE_POINT_COUNT) {
327 return;
328 }
329 OffsetF pointBegin = GetCircleCenterByXY(offset, choosePoint_[count - ANIMATABLE_POINT_COUNT].GetColumn(),
330 choosePoint_[count - ANIMATABLE_POINT_COUNT].GetRow());
331 OffsetF pointEnd = GetConnectedLineTailPoint();
332 if (pointEnd != pointBegin) {
333 path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
334 path.LineTo(pointEnd.GetX(), pointEnd.GetY());
335 }
336 }
337
AddCanceledLineToPath(RSPath & path,const OffsetF & offset)338 void PatternLockModifier::AddCanceledLineToPath(RSPath& path, const OffsetF& offset)
339 {
340 if (!needCanceledLine_) {
341 return;
342 }
343 size_t count = choosePoint_.size();
344 OffsetF pointBegin =
345 GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
346 OffsetF pointEnd = GetCanceledLineTailPoint();
347 if (pointEnd != pointBegin) {
348 path.MoveTo(pointBegin.GetX(), pointBegin.GetY());
349 path.LineTo(pointEnd.GetX(), pointEnd.GetY());
350 }
351 }
352
PaintLockCircle(RSCanvas & canvas,const OffsetF & offset,int32_t x,int32_t y)353 void PatternLockModifier::PaintLockCircle(RSCanvas& canvas, const OffsetF& offset, int32_t x, int32_t y)
354 {
355 auto activeColor = activeColor_->Get();
356 auto regularColor = regularColor_->Get();
357 auto selectedColor = selectedColor_->Get();
358 auto circleRadius = circleRadius_->Get();
359 auto pointAnimateColor = pointAnimateColor_->Get();
360 auto pathColor = pathColor_->Get();
361
362 OffsetF cellcenter = GetCircleCenterByXY(offset, x, y);
363 float offsetX = cellcenter.GetX();
364 float offsetY = cellcenter.GetY();
365
366 auto index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
367 if (CheckChoosePoint(x, y)) {
368 PaintCircle(canvas, offsetX, offsetY, GetBackgroundCircleRadius(index), ToRSColor(pathColor));
369 PaintLightRing(canvas, offsetX, offsetY, GetLightRingCircleRadius(index), GetLightRingAlphaF(index));
370 const int32_t lastIndexFir = 1;
371 CheckIsHoverAndPaint(canvas, offsetX, offsetY, GetActiveCircleRadius(index), index);
372 if (isMoveEventValid_->Get() && CheckChoosePointIsLastIndex(x, y, lastIndexFir)) {
373 PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(activeColor));
374 } else {
375 if (challengeResult_.has_value()) {
376 PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(pointAnimateColor));
377 } else {
378 PaintCircle(canvas, offsetX, offsetY, GetActiveCircleRadius(index), ToRSColor(selectedColor));
379 }
380 }
381 } else {
382 CheckIsHoverAndPaint(canvas, offsetX, offsetY, circleRadius, index);
383 PaintCircle(canvas, offsetX, offsetY, circleRadius, ToRSColor(regularColor));
384 }
385 }
386
CheckIsHoverAndPaint(RSCanvas & canvas,float offsetX,float offsetY,float radius,int32_t index)387 void PatternLockModifier::CheckIsHoverAndPaint(
388 RSCanvas& canvas, float offsetX, float offsetY, float radius, int32_t index)
389 {
390 if (isHover_->Get() && hoverIndex_->Get() == index) {
391 PaintCircle(canvas, offsetX, offsetY, radius * hoverRadiusScale_, ToRSColor(hoverColor_->Get()));
392 }
393 }
394
PaintCircle(RSCanvas & canvas,float offsetX,float offsetY,float radius,const RSColor & circleColor)395 void PatternLockModifier::PaintCircle(
396 RSCanvas& canvas, float offsetX, float offsetY, float radius, const RSColor& circleColor)
397 {
398 RSBrush brush;
399 brush.SetAntiAlias(true);
400 brush.SetColor(circleColor);
401 canvas.AttachBrush(brush);
402 canvas.DrawCircle(RSPoint(offsetX, offsetY), radius);
403 canvas.DetachBrush();
404 }
405
PaintLightRing(RSCanvas & canvas,float offsetX,float offsetY,float radius,float alphaF)406 void PatternLockModifier::PaintLightRing(RSCanvas& canvas, float offsetX, float offsetY, float radius, float alphaF)
407 {
408 if (NearZero(alphaF)) {
409 return;
410 }
411 RSPen pen;
412 pen.SetWidth(LIGHT_RING_LINE_WIDTH.ConvertToPx());
413 pen.SetAntiAlias(true);
414 pen.SetColor(ToRSColor(activeColor_->Get()));
415 pen.SetAlphaF(alphaF);
416 RSFilter filter;
417 filter.SetMaskFilter(RSMaskFilter::CreateBlurMaskFilter(
418 RSBlurType::NORMAL, RSDrawing::ConvertRadiusToSigma(LIGHT_RING_MASK_RADIUS.ConvertToPx())));
419 pen.SetFilter(filter);
420
421 canvas.AttachPen(pen);
422 RSPath path;
423 path.AddCircle(offsetX, offsetY, radius);
424 canvas.DrawPath(path);
425 canvas.DetachPen();
426 }
427
CheckChoosePoint(int32_t x,int32_t y) const428 bool PatternLockModifier::CheckChoosePoint(int32_t x, int32_t y) const
429 {
430 for (auto it : choosePoint_) {
431 if (it.GetColumn() == x && it.GetRow() == y) {
432 return true;
433 }
434 }
435 return false;
436 }
437
CheckChoosePointIsLastIndex(int32_t x,int32_t y,int32_t index) const438 bool PatternLockModifier::CheckChoosePointIsLastIndex(int32_t x, int32_t y, int32_t index) const
439 {
440 if (!choosePoint_.empty() && static_cast<int32_t>(choosePoint_.size()) >= index) {
441 if (choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetColumn() == x &&
442 choosePoint_.at(choosePoint_.size() - static_cast<uint32_t>(index)).GetRow() == y) {
443 return true;
444 }
445 }
446 return false;
447 }
448
GetCircleCenterByXY(const OffsetF & offset,int32_t x,int32_t y)449 OffsetF PatternLockModifier::GetCircleCenterByXY(const OffsetF& offset, int32_t x, int32_t y)
450 {
451 float sideLength = sideLength_->Get();
452 OffsetF cellCenter;
453 int32_t scale = RADIUS_TO_DIAMETER;
454 cellCenter.SetX(offset.GetX() + sideLength / PATTERN_LOCK_COL_COUNT / scale * (x * scale - 1));
455 cellCenter.SetY(offset.GetY() + sideLength / PATTERN_LOCK_COL_COUNT / scale * (y * scale - 1));
456 return cellCenter;
457 }
458
SetSideLength(float sideLength)459 void PatternLockModifier::SetSideLength(float sideLength)
460 {
461 CHECK_NULL_VOID(sideLength_);
462 if (!NearEqual(sideLength_->Get(), sideLength)) {
463 sideLength_->Set(sideLength);
464 size_t count = choosePoint_.size();
465 if (count > 0) {
466 OffsetF lastPoint = GetCircleCenterByXY(
467 offset_->Get(), choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
468 connectedLineTailPoint_->Set(lastPoint);
469 canceledLineTailPoint_->Set(lastPoint);
470 }
471 }
472 }
473
SetCircleRadius(float circleRadius)474 void PatternLockModifier::SetCircleRadius(float circleRadius)
475 {
476 CHECK_NULL_VOID(circleRadius_);
477 auto sideLength = sideLength_->Get();
478 if (NearZero(scaleBackgroundCircleRadius_)) {
479 return;
480 }
481 float handleCircleRadius =
482 std::min(circleRadius, sideLength / scaleBackgroundCircleRadius_ / PATTERN_LOCK_COL_COUNT * DIAMETER_TO_RADIUS);
483 circleRadius = std::max(handleCircleRadius, 0.0f);
484 if (!NearEqual(circleRadius_->Get(), circleRadius)) {
485 circleRadius_->Set(circleRadius);
486 for (const auto& cell : choosePoint_) {
487 auto index = (cell.GetColumn() - 1) * PATTERN_LOCK_COL_COUNT + cell.GetRow() - 1;
488 if (index < PATTERN_LOCK_POINT_COUNT && index >= 0) {
489 backgroundCircleRadius_.at(index)->Set(circleRadius * scaleBackgroundCircleRadius_);
490 activeCircleRadius_.at(index)->Set(circleRadius * scaleActiveCircleRadius_);
491 lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusStart_);
492 }
493 }
494 }
495 }
496
SetRegularColor(const Color & regularColor)497 void PatternLockModifier::SetRegularColor(const Color& regularColor)
498 {
499 CHECK_NULL_VOID(regularColor_);
500 regularColor_->Set(regularColor);
501 }
502
SetSelectColor(const Color & selectedColor)503 void PatternLockModifier::SetSelectColor(const Color& selectedColor)
504 {
505 CHECK_NULL_VOID(selectedColor_);
506 if (selectedColor_->Get() != selectedColor) {
507 selectedColor_->Set(selectedColor);
508 }
509 }
510
SetActiveColor(const Color & activeColor)511 void PatternLockModifier::SetActiveColor(const Color& activeColor)
512 {
513 CHECK_NULL_VOID(activeColor_);
514 activeColor_->Set(activeColor);
515 }
516
SetPathColor(const LinearColor & pathColor)517 void PatternLockModifier::SetPathColor(const LinearColor& pathColor)
518 {
519 CHECK_NULL_VOID(pathColor_);
520 pathColor_->Set(pathColor);
521 }
522
SetHoverColor(const Color & hoverColor)523 void PatternLockModifier::SetHoverColor(const Color& hoverColor)
524 {
525 CHECK_NULL_VOID(hoverColor_);
526 if (hoverColor_->Get() != hoverColor) {
527 hoverColor_->Set(hoverColor);
528 }
529 }
530
SetWrongColor(const Color & wrongColor)531 void PatternLockModifier::SetWrongColor(const Color& wrongColor)
532 {
533 CHECK_NULL_VOID(wrongColor_);
534 if (wrongColor_->Get() != wrongColor) {
535 wrongColor_->Set(wrongColor);
536 }
537 }
538
SetCorrectColor(const Color & correctColor)539 void PatternLockModifier::SetCorrectColor(const Color& correctColor)
540 {
541 CHECK_NULL_VOID(correctColor_);
542 correctColor_->Set(correctColor);
543 }
544
SetPathStrokeWidth(float pathStrokeWidth)545 void PatternLockModifier::SetPathStrokeWidth(float pathStrokeWidth)
546 {
547 CHECK_NULL_VOID(pathStrokeWidth_);
548 pathStrokeWidth_->Set(pathStrokeWidth);
549 }
550
SetContentOffset(const OffsetF & offset)551 void PatternLockModifier::SetContentOffset(const OffsetF& offset)
552 {
553 CHECK_NULL_VOID(offset_);
554 if (!NearEqual(offset_->Get(), offset)) {
555 offset_->Set(offset);
556 size_t count = choosePoint_.size();
557 if (count > 0) {
558 OffsetF lastPoint =
559 GetCircleCenterByXY(offset, choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
560 connectedLineTailPoint_->Set(lastPoint);
561 canceledLineTailPoint_->Set(lastPoint);
562 }
563 }
564 }
565
SetIsMoveEventValid(bool isMoveEventValid)566 void PatternLockModifier::SetIsMoveEventValid(bool isMoveEventValid)
567 {
568 isMoveEventValid_->Set(isMoveEventValid);
569 }
570
SetIsHover(bool isHover)571 void PatternLockModifier::SetIsHover(bool isHover)
572 {
573 isHover_->Set(isHover);
574 }
575
SetHoverIndex(int32_t hoverIndex)576 void PatternLockModifier::SetHoverIndex(int32_t hoverIndex)
577 {
578 hoverIndex_->Set(hoverIndex);
579 }
580
StartChallengeResultAnimate()581 void PatternLockModifier::StartChallengeResultAnimate()
582 {
583 if (!challengeResult_.has_value()) {
584 return;
585 }
586 if (challengeResult_.value() == NG::PatternLockChallengeResult::CORRECT) {
587 pointAnimateColor_->Set(LinearColor(selectedColor_->Get()));
588 AnimationOption option = AnimationOption();
589 option.SetDuration(CONNECT_ANIMATION_DURATION_FIRST);
590 option.SetCurve(Curves::SHARP);
591 AnimationUtils::Animate(option, [&]() { pointAnimateColor_->Set(LinearColor(correctColor_->Get())); });
592 } else if (challengeResult_.value() == NG::PatternLockChallengeResult::WRONG) {
593 pointAnimateColor_->Set(LinearColor(wrongColor_->Get()));
594 auto pathColor = pathColor_->Get();
595 AnimationOption option = AnimationOption();
596 option.SetDuration(WRONG_ANIMATION_DURATION_FLASH_TWICE);
597 option.SetCurve(Curves::SHARP);
598 auto dimmingAnimation = [weak = WeakClaim(this)]() {
599 auto modifier = weak.Upgrade();
600 CHECK_NULL_VOID(modifier);
601 modifier->pointAnimateColor_->Set(
602 LinearColor(modifier->wrongColor_->Get().BlendOpacity(FLASH_POINT_OPACITY)));
603 modifier->SetPathColor(LinearColor(modifier->pathColor_->Get().BlendOpacity(FLASH_POINT_OPACITY)));
604 };
605 auto brighteningAnimation = [weak = WeakClaim(this), pathColor]() {
606 auto modifier = weak.Upgrade();
607 CHECK_NULL_VOID(modifier);
608 modifier->pointAnimateColor_->Set(LinearColor(modifier->wrongColor_->Get()));
609 modifier->SetPathColor(pathColor);
610 };
611 AnimationUtils::OpenImplicitAnimation(option, Curves::SHARP, nullptr);
612 AnimationUtils::AddKeyFrame(((float)WRONG_ANIMATION_DURATION_DIMMING / WRONG_ANIMATION_DURATION_FLASH_TWICE),
613 Curves::SHARP, dimmingAnimation);
614 AnimationUtils::AddKeyFrame(((float)WRONG_ANIMATION_DURATION_FLASH_ONCE / WRONG_ANIMATION_DURATION_FLASH_TWICE),
615 Curves::SHARP, brighteningAnimation);
616 AnimationUtils::AddKeyFrame(((float)(WRONG_ANIMATION_DURATION_FLASH_ONCE + WRONG_ANIMATION_DURATION_DIMMING) /
617 WRONG_ANIMATION_DURATION_FLASH_TWICE),
618 Curves::SHARP, dimmingAnimation);
619 AnimationUtils::AddKeyFrame(1.0f, Curves::SHARP, brighteningAnimation);
620 AnimationUtils::CloseImplicitAnimation();
621 }
622 }
623
SetChallengeResult(std::optional<NG::PatternLockChallengeResult> & challengeResult)624 void PatternLockModifier::SetChallengeResult(std::optional<NG::PatternLockChallengeResult>& challengeResult)
625 {
626 if (challengeResult_ != challengeResult) {
627 challengeResult_ = challengeResult;
628 StartChallengeResultAnimate();
629 }
630 }
631
SetCellCenterOffset(const OffsetF & cellcenter)632 void PatternLockModifier::SetCellCenterOffset(const OffsetF& cellcenter)
633 {
634 CHECK_NULL_VOID(cellCenter_);
635 cellCenter_->Set(cellcenter);
636 }
637
SetChoosePoint(const std::vector<PatternLockCell> & choosePoint)638 void PatternLockModifier::SetChoosePoint(const std::vector<PatternLockCell>& choosePoint)
639 {
640 choosePoint_ = choosePoint;
641 }
642
SetActiveCircleRadiusScale(float scale)643 void PatternLockModifier::SetActiveCircleRadiusScale(float scale)
644 {
645 scaleActiveCircleRadius_ = scale;
646 }
647
SetBackgroundCircleRadiusScale(float scale)648 void PatternLockModifier::SetBackgroundCircleRadiusScale(float scale)
649 {
650 scaleBackgroundCircleRadius_ = scale;
651 }
652
SetLightRingRadiusStartScale(float scale)653 void PatternLockModifier::SetLightRingRadiusStartScale(float scale)
654 {
655 scaleLightRingRadiusStart_ = scale;
656 }
657
SetLightRingRadiusEndScale(float scale)658 void PatternLockModifier::SetLightRingRadiusEndScale(float scale)
659 {
660 scaleLightRingRadiusEnd_ = scale;
661 }
662
SetHoverRadiusScale(float scale)663 void PatternLockModifier::SetHoverRadiusScale(float scale)
664 {
665 hoverRadiusScale_ = scale;
666 }
667
SetBackgroundCircleRadius(int32_t index)668 void PatternLockModifier::SetBackgroundCircleRadius(int32_t index)
669 {
670 if (index < static_cast<int32_t>(backgroundCircleRadius_.size()) && index >= 0) {
671 backgroundCircleRadius_.at(index)->Set(0.0f);
672 AnimationOption option = AnimationOption();
673 auto curve = AceType::MakeRefPtr<ResponsiveSpringMotion>(
674 BACKGROUND_RADIUS_SPRING_RESPONSE, BACKGROUND_RADIUS_SPRING_DAMPING);
675 option.SetCurve(curve);
676 AnimationUtils::Animate(option,
677 [&]() { backgroundCircleRadius_.at(index)->Set(circleRadius_->Get() * scaleBackgroundCircleRadius_); });
678 }
679 }
680
GetBackgroundCircleRadius(int32_t index) const681 float PatternLockModifier::GetBackgroundCircleRadius(int32_t index) const
682 {
683 if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
684 return 0;
685 }
686 return backgroundCircleRadius_.at(index)->Get();
687 }
688
SetActiveCircleRadius(int32_t index)689 void PatternLockModifier::SetActiveCircleRadius(int32_t index)
690 {
691 if (index < static_cast<int32_t>(activeCircleRadius_.size()) && index >= 0) {
692 activeCircleRadius_.at(index)->Set(circleRadius_->Get());
693 AnimationOption option = AnimationOption();
694 option.SetDuration(ACTIVE_RADIUS_ANIMATION_DURATION);
695 option.SetCurve(Curves::FRICTION);
696 AnimationUtils::Animate(
697 option, [&]() { activeCircleRadius_.at(index)->Set(circleRadius_->Get() * scaleActiveCircleRadius_); });
698 }
699 }
700
GetActiveCircleRadius(int32_t index) const701 float PatternLockModifier::GetActiveCircleRadius(int32_t index) const
702 {
703 if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
704 return 0;
705 }
706 return activeCircleRadius_.at(index)->Get();
707 }
708
SetLightRingCircleRadius(int32_t index)709 void PatternLockModifier::SetLightRingCircleRadius(int32_t index)
710 {
711 if (index < static_cast<int32_t>(lightRingRadius_.size()) && index >= 0) {
712 auto circleRadius = circleRadius_->Get();
713 lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusStart_);
714 AnimationOption option = AnimationOption();
715 option.SetDuration(LIGHT_RING_RADIUS_ANIMATION_DURATION);
716 option.SetCurve(Curves::LINEAR);
717 AnimationUtils::Animate(
718 option, [&]() { lightRingRadius_.at(index)->Set(circleRadius * scaleLightRingRadiusEnd_); });
719 }
720 }
721
GetLightRingCircleRadius(int32_t index) const722 float PatternLockModifier::GetLightRingCircleRadius(int32_t index) const
723 {
724 if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
725 return 0;
726 }
727 return lightRingRadius_.at(index)->Get();
728 }
729
SetLightRingAlphaF(int32_t index)730 void PatternLockModifier::SetLightRingAlphaF(int32_t index)
731 {
732 if (index < static_cast<int32_t>(lightRingAlphaF_.size()) && index >= 0) {
733 auto singleLightRingAlphaF = lightRingAlphaF_.at(index);
734 singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_START);
735 AnimationOption optionFirst = AnimationOption();
736 optionFirst.SetDuration(LIGHT_RING_ALPHAF_ANIMATION_DURATION_FIRST);
737 optionFirst.SetCurve(Curves::SHARP);
738 optionFirst.SetOnFinishEvent([=] {
739 AnimationOption optionSecond = AnimationOption();
740 optionSecond.SetDuration(LIGHT_RING_ALPHAF_ANIMATION_DURATION_SECOND);
741 optionSecond.SetCurve(Curves::SHARP);
742 AnimationUtils::Animate(optionSecond, [=]() { singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_START); });
743 });
744 AnimationUtils::Animate(
745 optionFirst, [&]() { singleLightRingAlphaF->Set(LIGHT_RING_ALPHAF_END); }, optionFirst.GetOnFinishEvent());
746 }
747 }
748
GetLightRingAlphaF(int32_t index) const749 float PatternLockModifier::GetLightRingAlphaF(int32_t index) const
750 {
751 if ((index >= PATTERN_LOCK_POINT_COUNT || index < 0)) {
752 return 0;
753 }
754 return lightRingAlphaF_.at(index)->Get();
755 }
756
SetConnectedLineTailPoint(int32_t x,int32_t y)757 void PatternLockModifier::SetConnectedLineTailPoint(int32_t x, int32_t y)
758 {
759 size_t count = choosePoint_.size();
760 if (count < 1) {
761 return;
762 }
763 OffsetF lastPoint = GetCircleCenterByXY(offset_->Get(), x, y);
764 if (isTouchDown_ && isMoveEventValid_) {
765 connectedLineTailPoint_->Set(cellCenter_->Get());
766 AnimationOption option = AnimationOption();
767 auto curve =
768 AceType::MakeRefPtr<ResponsiveSpringMotion>(CONNECTED_LINE_SPRING_RESPONSE, CONNECTED_LINE_SPRING_DAMPING);
769 option.SetCurve(curve);
770 AnimationUtils::Animate(option, [&]() { connectedLineTailPoint_->Set(lastPoint); });
771 } else {
772 connectedLineTailPoint_->Set(lastPoint);
773 }
774 }
775
GetConnectedLineTailPoint() const776 OffsetF PatternLockModifier::GetConnectedLineTailPoint() const
777 {
778 return connectedLineTailPoint_->Get();
779 }
780
SetCanceledLineTailPoint()781 void PatternLockModifier::SetCanceledLineTailPoint()
782 {
783 size_t count = choosePoint_.size();
784 if (count < 1) {
785 return;
786 }
787
788 canceledLineTailPoint_->Set(GetPointEndByCellCenter());
789 OffsetF pointEnd =
790 GetCircleCenterByXY(offset_->Get(), choosePoint_[count - 1].GetColumn(), choosePoint_[count - 1].GetRow());
791 AnimationOption option = AnimationOption();
792 auto curve =
793 AceType::MakeRefPtr<ResponsiveSpringMotion>(CANCELED_LINE_SPRING_RESPONSE, CANCELED_LINE_SPRING_DAMPING);
794 option.SetCurve(curve);
795 AnimationUtils::Animate(option, [&]() { canceledLineTailPoint_->Set(pointEnd); });
796 }
797
GetCanceledLineTailPoint() const798 OffsetF PatternLockModifier::GetCanceledLineTailPoint() const
799 {
800 return canceledLineTailPoint_->Get();
801 }
802
StartConnectedCircleAnimate(int32_t x,int32_t y)803 void PatternLockModifier::StartConnectedCircleAnimate(int32_t x, int32_t y)
804 {
805 auto index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
806 SetBackgroundCircleRadius(index);
807 SetActiveCircleRadius(index);
808 SetLightRingCircleRadius(index);
809 SetLightRingAlphaF(index);
810 }
811
StartConnectedLineAnimate(int32_t x,int32_t y)812 void PatternLockModifier::StartConnectedLineAnimate(int32_t x, int32_t y)
813 {
814 SetConnectedLineTailPoint(x, y);
815 }
816
StartCanceledAnimate()817 void PatternLockModifier::StartCanceledAnimate()
818 {
819 SetCanceledLineTailPoint();
820 }
821
Reset()822 void PatternLockModifier::Reset()
823 {
824 SetIsTouchDown(false);
825 needCanceledLine_ = false;
826 challengeResult_.reset();
827 connectedLineTailPoint_->Set(OffsetF());
828 canceledLineTailPoint_->Set(OffsetF());
829 for (auto& radius : backgroundCircleRadius_) {
830 radius->Set(0.0f);
831 }
832 for (auto& radius : activeCircleRadius_) {
833 radius->Set(circleRadius_->Get());
834 }
835 for (auto& radius : lightRingRadius_) {
836 radius->Set(circleRadius_->Get() * scaleLightRingRadiusStart_);
837 }
838 for (auto& alphaF : lightRingAlphaF_) {
839 alphaF->Set(LIGHT_RING_ALPHAF_START);
840 }
841 }
842
SetIsTouchDown(bool isTouchDown)843 void PatternLockModifier::SetIsTouchDown(bool isTouchDown)
844 {
845 if (isTouchDown_ && (!isTouchDown)) {
846 needCanceledLine_ = true;
847 } else if ((!isTouchDown_) && isTouchDown) {
848 needCanceledLine_ = false;
849 }
850 isTouchDown_ = isTouchDown;
851 }
852
GetPointEndByCellCenter() const853 OffsetF PatternLockModifier::GetPointEndByCellCenter() const
854 {
855 auto offset = offset_->Get();
856 float sideLength = sideLength_->Get();
857 auto cellCenter = cellCenter_->Get();
858 float x = cellCenter.GetX();
859 float y = cellCenter.GetY();
860 x = x > offset.GetX() + sideLength ? offset.GetX() + sideLength : x;
861 x = x < offset.GetX() ? offset.GetX() : x;
862 y = y > offset.GetY() + sideLength ? offset.GetY() + sideLength : y;
863 y = y < offset.GetY() ? offset.GetY() : y;
864 return OffsetF(x, y);
865 }
866
SetCircleClip(RSCanvas & canvas)867 void PatternLockModifier::SetCircleClip(RSCanvas& canvas)
868 {
869 int32_t x = 0;
870 int32_t y = 0;
871 int32_t index = 0;
872 OffsetF center;
873 float backgroundCircleRadius = 0.0f;
874 float activeCircleRadius = 0.0f;
875 float clipRadius = 0.0f;
876 RSPath path;
877 for (const auto& point : choosePoint_) {
878 x = point.GetColumn();
879 y = point.GetRow();
880 center = GetCircleCenterByXY(offset_->Get(), x, y);
881 index = (x - 1) * PATTERN_LOCK_COL_COUNT + y - 1;
882 backgroundCircleRadius = GetBackgroundCircleRadius(index);
883 activeCircleRadius = GetActiveCircleRadius(index);
884 clipRadius = backgroundCircleRadius > activeCircleRadius ? backgroundCircleRadius : activeCircleRadius;
885 path.AddCircle(center.GetX(), center.GetY(), clipRadius);
886 }
887 canvas.ClipPath(path, RSClipOp::DIFFERENCE, true);
888 }
889 } // namespace OHOS::Ace::NG
890