1 /*
2 * Copyright (c) 2021-2022 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/dialog_tween/render_dialog_tween.h"
17
18 #include "base/log/event_report.h"
19 #include "core/components/dialog/dialog_theme.h"
20 #include "core/components/stack/stack_element.h"
21 #include "core/event/ace_event_helper.h"
22
23 namespace OHOS::Ace {
24 namespace {
25
26 // Using UX spec: Constrain max height within 4/5 of screen height.
27 constexpr double DIALOG_HEIGHT_RATIO = 0.8;
28 constexpr double DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE = 0.9;
29 constexpr double DIALOG_HEIGHT_RATIO_FOR_CAR = 0.95;
30 constexpr double DIALOG_DRAG_RATIO = 0.5;
31 constexpr int32_t POSITIVE_SUCCESS_ID = 0;
32 constexpr int32_t NEGATIVE_SUCCESS_ID = 1;
33 constexpr int32_t NEUTRAL_SUCCESS_ID = 2;
34
35 } // namespace
36
RenderDialogTween()37 RenderDialogTween::RenderDialogTween()
38 {
39 clickDetector_ = AceType::MakeRefPtr<ClickRecognizer>();
40 clickDetector_->SetOnClick([weak = WeakClaim(this)](const ClickInfo& info) {
41 auto dialog = weak.Upgrade();
42 if (dialog) {
43 dialog->HandleClick(info.GetLocalLocation());
44 }
45 });
46 dragDetector_ = AceType::MakeRefPtr<DragRecognizer>(Axis::FREE);
47 dragDetector_->SetOnDragStart([weak = WeakClaim(this)](const DragStartInfo& startInfo) {
48 auto dialog = weak.Upgrade();
49 if (dialog) {
50 dialog->dragStart_ = startInfo.GetLocalLocation().GetX();
51 dialog->dragY_ = startInfo.GetLocalLocation().GetY();
52 dialog->dragX_ = startInfo.GetLocalLocation().GetX();
53 dialog->lastPositionX_ = startInfo.GetLocalLocation().GetX();
54 dialog->lastPositionY_ = startInfo.GetLocalLocation().GetY();
55 dialog->init_ = false;
56 if (dialog->maskDragRegion_.ContainsInRegion(dialog->dragX_, dialog->dragY_)) {
57 dialog->isDragging_ = true;
58 } else {
59 dialog->isDragging_ = false;
60 }
61 }
62 });
63 dragDetector_->SetOnDragEnd([weak = WeakClaim(this)](const DragEndInfo& endInfo) {
64 auto dialog = weak.Upgrade();
65 if (dialog) {
66 double dragEnd = endInfo.GetLocalLocation().GetX();
67 if (!dialog->isDragging_ &&
68 GreatOrEqual(dragEnd - dialog->dragStart_, dialog->GetLayoutSize().Width() * DIALOG_DRAG_RATIO)) {
69 dialog->PopDialog();
70 }
71 dialog->lastPositionX_ = endInfo.GetLocalLocation().GetX();
72 dialog->lastPositionY_ = endInfo.GetLocalLocation().GetY();
73 }
74 });
75 dragDetector_->SetOnDragUpdate([weak = WeakClaim(this)](const DragUpdateInfo& info) {
76 auto dialog = weak.Upgrade();
77 if (dialog) {
78 if (dialog->isDragable_ && dialog->isDragging_) {
79 dialog->HandleDragUpdate(info.GetLocalLocation());
80 }
81 }
82 });
83 init_ = true;
84 }
85
~RenderDialogTween()86 RenderDialogTween::~RenderDialogTween()
87 {
88 if (!popDialog_ && onStatusChanged_) {
89 onStatusChanged_(false);
90 popDialog_ = true;
91 }
92 auto dialogTweenComponent = weakDialogTweenComponent_.Upgrade();
93 if (dialogTweenComponent) {
94 RemoveBackendEvent(dialogTweenComponent);
95 }
96
97 auto accessibilityNode = accessibilityNode_.Upgrade();
98 if (accessibilityNode) {
99 accessibilityNode->ClearRect();
100 }
101 }
102
Create()103 RefPtr<RenderNode> RenderDialogTween::Create()
104 {
105 return AceType::MakeRefPtr<RenderDialogTween>();
106 }
107
Update(const RefPtr<Component> & component)108 void RenderDialogTween::Update(const RefPtr<Component>& component)
109 {
110 const RefPtr<DialogTweenComponent> dialog = AceType::DynamicCast<DialogTweenComponent>(component);
111 if (!dialog) {
112 LOGE("RenderDialogTween update with nullptr");
113 EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
114 return;
115 }
116 weakDialogTweenComponent_ = dialog;
117 autoCancel_ = dialog->GetAutoCancel();
118 onSuccess_ = AceAsyncEvent<void(int32_t)>::Create(dialog->GetOnSuccessId(), context_);
119 onCancel_ = AceAsyncEvent<void()>::Create(dialog->GetOnCancelId(), context_);
120 onComplete_ = AceAsyncEvent<void()>::Create(dialog->GetOnCompleteId(), context_);
121 onStatusChanged_ = dialog->GetOnStatusChanged();
122 animator_ = dialog->GetParentAnimator();
123 composedId_ = dialog->GetComposedId();
124 dialogId_ = dialog->GetDialogId();
125 customDialogId_ = dialog->GetCustomDialogId();
126 data_ = dialog->GetData();
127 isLimit_ = dialog->GetDialogLimit();
128 isSetMargin_ = dialog->IsSetMargin();
129 isDragable_ = dialog->IsDragable();
130 if (isSetMargin_) {
131 margin_ = dialog->GetMargin();
132 }
133 alignment_ = dialog->GetAlignment();
134 offset_ = dialog->GetOffset();
135 gridCount_ = dialog->GetGridCount();
136
137 if (dialog->IsMenu()) {
138 auto menuSuccessId = dialog->GetMenuSuccessId();
139 for (size_t index = 0; index < menuSuccessId.size(); ++index) {
140 const auto context = GetContext().Upgrade();
141 if (context && context->GetIsDeclarative()) {
142 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
143 menuSuccessId[index], [weak = WeakClaim(this), index](const ClickInfo& info) {
144 auto dialog = weak.Upgrade();
145 dialog->CallOnSuccess(index);
146 });
147 } else {
148 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
149 menuSuccessId[index], [weak = WeakClaim(this), index]() {
150 auto dialog = weak.Upgrade();
151 dialog->CallOnSuccess(index);
152 });
153 }
154 }
155 }
156 BindButtonEvent(dialog);
157 MarkNeedLayout();
158 }
159
BindButtonEvent(const RefPtr<DialogTweenComponent> & dialog)160 void RenderDialogTween::BindButtonEvent(const RefPtr<DialogTweenComponent>& dialog)
161 {
162 auto context = context_.Upgrade();
163 if (context && context->GetIsDeclarative()) {
164 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
165 dialog->GetOnPositiveSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
166 auto dialog = weak.Upgrade();
167 dialog->CallOnSuccess(POSITIVE_SUCCESS_ID);
168 });
169
170 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
171 dialog->GetOnNegativeSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
172 auto dialog = weak.Upgrade();
173 dialog->CallOnSuccess(NEGATIVE_SUCCESS_ID);
174 });
175
176 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
177 dialog->GetOnNeutralSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
178 auto dialog = weak.Upgrade();
179 dialog->CallOnSuccess(NEUTRAL_SUCCESS_ID);
180 });
181 return;
182 }
183
184 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
185 dialog->GetOnPositiveSuccessId(), [weak = WeakClaim(this)]() {
186 auto dialog = weak.Upgrade();
187 dialog->CallOnSuccess(POSITIVE_SUCCESS_ID);
188 });
189
190 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
191 dialog->GetOnNegativeSuccessId(), [weak = WeakClaim(this)]() {
192 auto dialog = weak.Upgrade();
193 dialog->CallOnSuccess(NEGATIVE_SUCCESS_ID);
194 });
195
196 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
197 dialog->GetOnNeutralSuccessId(), [weak = WeakClaim(this)]() {
198 auto dialog = weak.Upgrade();
199 dialog->CallOnSuccess(NEUTRAL_SUCCESS_ID);
200 });
201 }
202
HandleDragUpdate(const Offset & currentPoint)203 void RenderDialogTween::HandleDragUpdate(const Offset& currentPoint)
204 {
205 dragX_ = currentPoint.GetX();
206 dragY_ = currentPoint.GetY();
207 MarkNeedLayout();
208 }
209
CallOnSuccess(int32_t successType)210 void RenderDialogTween::CallOnSuccess(int32_t successType)
211 {
212 if (onStatusChanged_) {
213 popDialog_ = true;
214 }
215 const auto context = context_.Upgrade();
216 if (!context) {
217 LOGE("the context is null");
218 return;
219 }
220 const auto& lastStack = context->GetLastStack();
221 if (!lastStack) {
222 LOGE("the lastStack is null");
223 return;
224 }
225 if (animator_) {
226 animator_->AddStopListener([successType, lastStack, weak = WeakClaim(this), dialogId = dialogId_] {
227 auto dialog = weak.Upgrade();
228 if (!dialog) {
229 return;
230 }
231 lastStack->PopDialog(dialogId);
232 if (dialog->onSuccess_) {
233 dialog->onSuccess_(successType);
234 }
235 if (dialog->onComplete_) {
236 dialog->onComplete_();
237 }
238 if (dialog->onStatusChanged_) {
239 dialog->onStatusChanged_(false);
240 }
241 });
242 animator_->Play();
243 } else {
244 lastStack->PopDialog(dialogId_);
245 if (onSuccess_) {
246 onSuccess_(successType);
247 }
248 if (onComplete_) {
249 onComplete_();
250 }
251 if (onStatusChanged_) {
252 onStatusChanged_(false);
253 }
254 }
255 RemoveAccessibilityNode();
256 }
257
GetMaxWidthBasedOnGridType(const RefPtr<GridColumnInfo> & info,GridSizeType type,DeviceType deviceType)258 double RenderDialogTween::GetMaxWidthBasedOnGridType(
259 const RefPtr<GridColumnInfo>& info, GridSizeType type, DeviceType deviceType)
260 {
261 if (gridCount_ > 0) {
262 return info->GetWidth(std::min(gridCount_, info->GetParent()->GetColumns()));
263 }
264
265 if (deviceType == DeviceType::WATCH || deviceType == DeviceType::WEARABLE) {
266 if (type == GridSizeType::SM) {
267 return info->GetWidth(3);
268 } else if (type == GridSizeType::MD) {
269 return info->GetWidth(4);
270 } else if (type == GridSizeType::LG) {
271 return info->GetWidth(5);
272 } else {
273 LOGI("GetMaxWidthBasedOnGridType is undefined");
274 return info->GetWidth(5);
275 }
276 } else if (deviceType == DeviceType::PHONE) {
277 if (type == GridSizeType::SM) {
278 return info->GetWidth(4);
279 } else if (type == GridSizeType::MD) {
280 return info->GetWidth(5);
281 } else if (type == GridSizeType::LG) {
282 return info->GetWidth(6);
283 } else {
284 LOGI("GetMaxWidthBasedOnGridType is undefined");
285 return info->GetWidth(6);
286 }
287 } else if (deviceType == DeviceType::CAR) {
288 if (type == GridSizeType::SM) {
289 return info->GetWidth(4);
290 } else if (type == GridSizeType::MD) {
291 return info->GetWidth(6);
292 } else if (type == GridSizeType::LG) {
293 return info->GetWidth(8);
294 } else {
295 LOGI("GetMaxWidthBasedOnGridType is undefined");
296 return info->GetWidth(8);
297 }
298 } else {
299 if (type == GridSizeType::SM) {
300 return info->GetWidth(2);
301 } else if (type == GridSizeType::MD) {
302 return info->GetWidth(3);
303 } else if (type == GridSizeType::LG) {
304 return info->GetWidth(4);
305 } else {
306 LOGI("GetMaxWidthBasedOnGridType is undefined");
307 return info->GetWidth(4);
308 }
309 }
310 }
311
PerformLayout()312 void RenderDialogTween::PerformLayout()
313 {
314 LayoutParam innerLayout = GetLayoutParam();
315 auto maxSize = innerLayout.GetMaxSize();
316 // If max size is INFINITE, use viewport of parent.
317 if (maxSize == Size(std::numeric_limits<double>::max(), std::numeric_limits<double>::max())) {
318 auto parent = GetParent().Upgrade();
319 if (parent) {
320 maxSize = parent->GetChildViewPort();
321 }
322 }
323 innerLayout.SetMaxSize(maxSize);
324 ComputeInnerLayoutParam(innerLayout);
325 if (GetChildren().empty()) {
326 SetLayoutSize(maxSize);
327 return;
328 }
329 const auto& child = GetChildren().front();
330 child->Layout(innerLayout);
331 auto childSize = child->GetLayoutSize();
332 topLeftPoint_ = ComputeChildPosition(childSize);
333 child->SetPosition(topLeftPoint_);
334 UpdateTouchRegion(topLeftPoint_, maxSize, childSize);
335 SetLayoutSize(maxSize);
336 lastPositionX_ = dragX_;
337 lastPositionY_ = dragY_;
338 }
339
ComputeInnerLayoutParam(LayoutParam & innerLayout)340 void RenderDialogTween::ComputeInnerLayoutParam(LayoutParam& innerLayout)
341 {
342 auto maxSize = innerLayout.GetMaxSize();
343 // Set different layout param for different devices
344 auto gridSizeType = ScreenSystemManager::GetInstance().GetSize(maxSize.Width());
345 RefPtr<GridColumnInfo> columnInfo;
346 auto deviceType = SystemProperties::GetDeviceType();
347 if (deviceType == DeviceType::CAR) {
348 columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::CAR_DIALOG);
349 } else {
350 columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::DIALOG);
351 }
352 columnInfo->GetParent()->BuildColumnWidth(maxSize.Width());
353 auto width = GetMaxWidthBasedOnGridType(columnInfo, gridSizeType, deviceType);
354 if (!isLimit_) {
355 innerLayout.SetMinSize(Size(0.0, 0.0));
356 innerLayout.SetMaxSize(Size(maxSize.Width(), maxSize.Height()));
357 } else if (deviceType == DeviceType::WATCH || deviceType == DeviceType::WEARABLE) {
358 innerLayout.SetMinSize(Size(width, 0.0));
359 innerLayout.SetMaxSize(Size(width, maxSize.Height()));
360 } else if (deviceType == DeviceType::PHONE) {
361 if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
362 innerLayout.SetMinSize(Size(width, 0.0));
363 innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE));
364 } else {
365 innerLayout.SetMinSize(Size(width, 0.0));
366 innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO));
367 }
368 } else if (deviceType == DeviceType::CAR) {
369 innerLayout.SetMinSize(Size(width, 0.0));
370 innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_CAR));
371 } else {
372 innerLayout.SetMinSize(Size(width, 0.0));
373 innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO));
374 }
375 }
376
ComputeChildPosition(const Size & childSize) const377 Offset RenderDialogTween::ComputeChildPosition(const Size& childSize) const
378 {
379 Offset topLeftPoint;
380 auto context = context_.Upgrade();
381 auto theme = GetTheme<DialogTheme>();
382 if (!theme || !context) {
383 return topLeftPoint;
384 }
385
386 auto maxSize = GetLayoutParam().GetMaxSize();
387 // If max size is INFINITE, use viewport of parent.
388 if (maxSize == Size(std::numeric_limits<double>::max(), std::numeric_limits<double>::max())) {
389 auto parent = GetParent().Upgrade();
390 if (parent) {
391 maxSize = parent->GetChildViewPort();
392 }
393 }
394 if (isDragging_) {
395 topLeftPoint =
396 Offset(topLeftPoint_.GetX() + (dragX_ - lastPositionX_), topLeftPoint_.GetY() + (dragY_ - lastPositionY_));
397 return topLeftPoint;
398 }
399
400 Offset dialogOffset =
401 Offset(NormalizePercentToPx(offset_.GetX(), false, true), NormalizePercentToPx(offset_.GetY(), true, true));
402 if (offset_.GetX().Unit() == DimensionUnit::PERCENT) {
403 dialogOffset.SetX(offset_.GetX().Value() * childSize.Width());
404 } else {
405 dialogOffset.SetX(NormalizeToPx(offset_.GetX()));
406 }
407 if (offset_.GetY().Unit() == DimensionUnit::PERCENT) {
408 dialogOffset.SetY(offset_.GetY().Value() * childSize.Height());
409 } else {
410 dialogOffset.SetY(NormalizeToPx(offset_.GetY()));
411 }
412 if (init_) {
413 if (SetAlignmentSwitch(maxSize, childSize, topLeftPoint)) {
414 return topLeftPoint + dialogOffset;
415 }
416
417 if (context->GetIsDeclarative()) {
418 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
419 return topLeftPoint + dialogOffset;
420 }
421
422 // Set different positions for different devices
423 if (SystemProperties::GetDeviceType() == DeviceType::PHONE &&
424 SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
425 topLeftPoint = Offset((maxSize.Width() - childSize.Width()) / 2.0,
426 maxSize.Height() - childSize.Height() - (isSetMargin_ ? 0.0 : NormalizeToPx(theme->GetMarginBottom())));
427 } else {
428 topLeftPoint =
429 Offset((maxSize.Width() - childSize.Width()) / 2.0, (maxSize.Height() - childSize.Height()) / 2.0);
430 }
431 }
432 return topLeftPoint + dialogOffset;
433 }
434
SetAlignmentSwitch(const Size & maxSize,const Size & childSize,Offset & topLeftPoint) const435 bool RenderDialogTween::SetAlignmentSwitch(const Size& maxSize, const Size& childSize, Offset& topLeftPoint) const
436 {
437 // If alignment is setted, compute position with alignment and offset.
438 if (alignment_ != DialogAlignment::DEFAULT) {
439 switch (alignment_) {
440 case DialogAlignment::TOP:
441 topLeftPoint = Offset((maxSize.Width() - childSize.Width()) / 2.0, 0.0);
442 break;
443 case DialogAlignment::CENTER:
444 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
445 break;
446 case DialogAlignment::BOTTOM:
447 topLeftPoint =
448 Offset((maxSize.Width() - childSize.Width()) / 2.0, maxSize.Height() - childSize.Height());
449 break;
450 case DialogAlignment::TOP_START:
451 topLeftPoint = Offset(0.0, 0.0);
452 break;
453 case DialogAlignment::TOP_END:
454 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), 0.0);
455 break;
456 case DialogAlignment::CENTER_START:
457 topLeftPoint = Offset(0.0, maxSize.Height() - childSize.Height()) / 2.0;
458 break;
459 case DialogAlignment::CENTER_END:
460 topLeftPoint =
461 Offset(maxSize.Width() - childSize.Width(), (maxSize.Height() - childSize.Height()) / 2.0);
462 break;
463 case DialogAlignment::BOTTOM_START:
464 topLeftPoint = Offset(0.0, maxSize.Height() - childSize.Height());
465 break;
466 case DialogAlignment::BOTTOM_END:
467 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height());
468 break;
469 default:
470 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
471 break;
472 }
473 return true;
474 }
475 return false;
476 }
477
UpdateTouchRegion(const Offset & topLeftPoint,const Size & maxSize,const Size & childSize)478 void RenderDialogTween::UpdateTouchRegion(const Offset& topLeftPoint, const Size& maxSize, const Size& childSize)
479 {
480 double left = margin_.Left().Unit() == DimensionUnit::PERCENT ? margin_.Left().Value() * maxSize.Width()
481 : NormalizeToPx(margin_.Left());
482 double top = margin_.Top().Unit() == DimensionUnit::PERCENT ? margin_.Top().Value() * maxSize.Height()
483 : NormalizeToPx(margin_.Top());
484 Offset touchTopLeft = topLeftPoint + (isSetMargin_ ? Offset(left, top) : Offset(0.0, 0.0));
485
486 double right = margin_.Right().Unit() == DimensionUnit::PERCENT ? margin_.Right().Value() * maxSize.Width()
487 : NormalizeToPx(margin_.Right());
488 double bottom = margin_.Bottom().Unit() == DimensionUnit::PERCENT ? margin_.Bottom().Value() * maxSize.Height()
489 : NormalizeToPx(margin_.Bottom());
490 Offset touchBottomRight = topLeftPoint + childSize - (isSetMargin_ ? Offset(right, bottom) : Offset(0.0, 0.0));
491
492 Offset dragBottomRight = touchBottomRight;
493 dragBottomRight.SetY(touchTopLeft.GetY() + DRAG_BAR_HEIGHT);
494
495 maskTouchRegion_ = TouchRegion(touchTopLeft, touchBottomRight);
496 maskDragRegion_ = TouchRegion(touchTopLeft, dragBottomRight);
497 }
498
OnPaintFinish()499 void RenderDialogTween::OnPaintFinish()
500 {
501 InitAccessibilityEventListener();
502 if (onStatusChanged_) {
503 onStatusChanged_(true);
504 }
505 }
506
HandleClick(const Offset & clickPosition)507 void RenderDialogTween::HandleClick(const Offset& clickPosition)
508 {
509 if (autoCancel_ && !maskTouchRegion_.ContainsInRegion(clickPosition.GetX(), clickPosition.GetY())) {
510 PopDialog();
511 }
512 }
513
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)514 void RenderDialogTween::OnTouchTestHit(
515 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
516 {
517 clickDetector_->SetCoordinateOffset(coordinateOffset);
518 result.emplace_back(clickDetector_);
519 if (isDragable_) {
520 dragDetector_->SetCoordinateOffset(coordinateOffset);
521 result.emplace_back(dragDetector_);
522 }
523 }
524
PopDialog()525 bool RenderDialogTween::PopDialog()
526 {
527 if (onStatusChanged_) {
528 popDialog_ = true;
529 }
530 const auto context = context_.Upgrade();
531 if (!context) {
532 LOGE("the context is null");
533 return false;
534 }
535 const auto& lastStack = context->GetLastStack();
536 if (!lastStack) {
537 LOGE("the lastStack is null");
538 return false;
539 }
540 if (animator_) {
541 animator_->AddStopListener([lastStack, weak = AceType::WeakClaim(this), dialogId = dialogId_] {
542 auto dialog = weak.Upgrade();
543 if (!dialog) {
544 return;
545 }
546 lastStack->PopDialog(dialogId);
547 if (dialog->onCancel_) {
548 dialog->onCancel_();
549 }
550 if (dialog->onComplete_) {
551 dialog->onComplete_();
552 }
553 if (dialog->onStatusChanged_) {
554 dialog->onStatusChanged_(false);
555 }
556 });
557 animator_->Play();
558 } else {
559 lastStack->PopDialog(dialogId_);
560 if (onCancel_) {
561 onCancel_();
562 }
563 if (onComplete_) {
564 onComplete_();
565 }
566 if (onStatusChanged_) {
567 onStatusChanged_(false);
568 }
569 }
570 RemoveAccessibilityNode();
571 return true;
572 }
573
SetAnimator(const RefPtr<Animator> & animator)574 void RenderDialogTween::SetAnimator(const RefPtr<Animator>& animator)
575 {
576 animator_ = animator;
577 }
578
InitAccessibilityEventListener()579 void RenderDialogTween::InitAccessibilityEventListener()
580 {
581 const auto& accessibilityNode = GetAccessibilityNode().Upgrade();
582 if (!accessibilityNode) {
583 return;
584 }
585 accessibilityNode->SetFocusableState(true);
586 accessibilityNode->SetText(data_);
587
588 accessibilityNode->AddSupportAction(AceAction::CUSTOM_ACTION);
589 accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
590 accessibilityNode->AddSupportAction(AceAction::ACTION_FOCUS);
591 accessibilityNode->AddSupportAction(AceAction::ACTION_LONG_CLICK);
592 accessibilityNode->AddSupportAction(AceAction::GLOBAL_ACTION_BACK);
593 accessibilityNode->SetLongClickableState(true);
594
595 accessibilityNode->SetActionLongClickImpl([weakPtr = WeakClaim(this)]() {
596 const auto& dialogTween = weakPtr.Upgrade();
597 if (dialogTween) {
598 dialogTween->PopDialog();
599 }
600 });
601
602 // RenderDialogTween's size is 0*0, use parent's rect,
603 // or no child on dialog can get focused by click in accessibility mode
604 auto parent = accessibilityNode->GetParentNode();
605 if (parent) {
606 accessibilityNode->SetRect(parent->GetRect());
607 }
608 }
609
RemoveAccessibilityNode()610 void RenderDialogTween::RemoveAccessibilityNode()
611 {
612 auto context = context_.Upgrade();
613 if (!context) {
614 return;
615 }
616
617 const auto& accessibilityManager = context->GetAccessibilityManager();
618 if (accessibilityManager) {
619 // no new accessibility node is created with DialogTween in JS app
620 if (context->GetIsDeclarative()) {
621 accessibilityManager->RemoveAccessibilityNodeById(composedId_);
622 }
623 #if defined(PREVIEW)
624 auto node = accessibilityManager->GetAccessibilityNodeById(customDialogId_);
625 accessibilityManager->ClearNodeRectInfo(node, true);
626 #endif
627 }
628 }
629
RemoveBackendEvent(const RefPtr<DialogTweenComponent> & component)630 void RenderDialogTween::RemoveBackendEvent(const RefPtr<DialogTweenComponent>& component)
631 {
632 auto context = context_.Upgrade();
633 if (context && context->GetIsDeclarative()) {
634 BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
635 component->GetOnPositiveSuccessId());
636 BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
637 component->GetOnNegativeSuccessId());
638 BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
639 component->GetOnNeutralSuccessId());
640 } else {
641 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnPositiveSuccessId());
642 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnNegativeSuccessId());
643 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnNeutralSuccessId());
644 }
645 BackEndEventManager<void(int32_t)>::GetInstance().RemoveBackEndEvent(component->GetOnSuccessId());
646 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnCancelId());
647 BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnCompleteId());
648 }
649
HandleMouseEvent(const MouseEvent & event)650 bool RenderDialogTween::HandleMouseEvent(const MouseEvent& event)
651 {
652 if (event.button != MouseButton::NONE_BUTTON && event.button != MouseButton::LEFT_BUTTON &&
653 event.action == MouseAction::PRESS) {
654 HandleClick({ event.x, event.y });
655 }
656 return true;
657 }
658
659 } // namespace OHOS::Ace
660