• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
16 
17 #include "base/memory/ace_type.h"
18 #include "base/subwindow/subwindow.h"
19 #include "base/subwindow/subwindow_manager.h"
20 #include "base/utils/utils.h"
21 #include "core/common/container.h"
22 #include "core/common/container_scope.h"
23 #include "core/common/window_animation_config.h"
24 #include "core/components/common/properties/shadow_config.h"
25 #include "core/components/container_modal/container_modal_constants.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/base/ui_node.h"
28 #include "core/components_ng/pattern/bubble/bubble_layout_property.h"
29 #include "core/components_ng/pattern/bubble/bubble_render_property.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 #include "core/components_ng/property/property.h"
32 #include "core/components_v2/inspector/inspector_constants.h"
33 #include "core/event/touch_event.h"
34 #include "core/pipeline/pipeline_base.h"
35 #include "core/pipeline/pipeline_context.h"
36 #include "core/pipeline_ng/pipeline_context.h"
37 
38 namespace OHOS::Ace::NG {
39 namespace {
40 constexpr float VISIABLE_ALPHA = 1.0f;
41 constexpr float INVISIABLE_ALPHA = 0.0f;
42 constexpr int32_t ENTRY_ANIMATION_DURATION = 250;
43 constexpr int32_t EXIT_ANIMATION_DURATION = 100;
44 const Dimension INVISIABLE_OFFSET = 8.0_px;
45 } // namespace
46 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)47 bool BubblePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
48 {
49     if (skipMeasure && skipLayout) {
50         return false;
51     }
52     auto host = GetHost();
53     CHECK_NULL_RETURN(host, false);
54     auto paintProperty = host->GetPaintProperty<BubbleRenderProperty>();
55     CHECK_NULL_RETURN(paintProperty, false);
56     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
57     CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
58     auto bubbleLayoutAlgorithm = DynamicCast<BubbleLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
59     CHECK_NULL_RETURN(bubbleLayoutAlgorithm, false);
60 
61     showArrow_ = bubbleLayoutAlgorithm->ShowArrow();
62     arrowPosition_ = bubbleLayoutAlgorithm->GetArrowPosition();
63     childOffset_ = bubbleLayoutAlgorithm->GetChildOffset();
64     childSize_ = bubbleLayoutAlgorithm->GetChildSize();
65     touchRegion_ = bubbleLayoutAlgorithm->GetTouchRegion();
66     targetOffset_ = bubbleLayoutAlgorithm->GetTargetOffset();
67     targetSize_ = bubbleLayoutAlgorithm->GetTargetSize();
68     arrowPlacement_ = bubbleLayoutAlgorithm->GetArrowPlacement();
69     clipPath_ = bubbleLayoutAlgorithm->GetClipPath();
70     clipFrameNode_ = bubbleLayoutAlgorithm->GetClipFrameNode();
71     arrowOffsetsFromClip_ = bubbleLayoutAlgorithm->GetArrowOffsetsFromClip();
72     arrowWidth_ = bubbleLayoutAlgorithm->GetArrowWidth();
73     arrowHeight_ = bubbleLayoutAlgorithm->GetArrowHeight();
74     border_ = bubbleLayoutAlgorithm->GetBorder();
75     paintProperty->UpdatePlacement(bubbleLayoutAlgorithm->GetArrowPlacement());
76     if (delayShow_) {
77         delayShow_ = false;
78         if (transitionStatus_ == TransitionStatus::INVISIABLE) {
79             StartEnteringAnimation(nullptr);
80         }
81     }
82     return true;
83 }
84 
OnModifyDone()85 void BubblePattern::OnModifyDone()
86 {
87     if (SystemProperties::GetColorMode() != colorMode_ && !isCustomPopup_) {
88         colorMode_ = SystemProperties::GetColorMode();
89         UpdateBubbleText();
90     }
91     UpdateAgingTextSize();
92     Pattern::OnModifyDone();
93     InitTouchEvent();
94     RegisterButtonOnHover();
95     RegisterButtonOnTouch();
96 }
97 
AddPipelineCallBack()98 void BubblePattern::AddPipelineCallBack()
99 {
100     auto host = GetHost();
101     CHECK_NULL_VOID(host);
102     auto pipelineContext = PipelineContext::GetCurrentContext();
103     CHECK_NULL_VOID(pipelineContext);
104     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
105     pipelineContext->AddWindowStateChangedCallback(host->GetId());
106 }
107 
OnAttachToFrameNode()108 void BubblePattern::OnAttachToFrameNode()
109 {
110     auto host = GetHost();
111     CHECK_NULL_VOID(host);
112     host->GetRenderContext()->SetClipToFrame(true);
113 
114     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
115     CHECK_NULL_VOID(targetNode);
116     auto pipelineContext = host->GetContextRefPtr();
117     CHECK_NULL_VOID(pipelineContext);
118     hasOnAreaChange_ = pipelineContext->HasOnAreaChangeNode(targetNode->GetId());
119     auto eventHub = targetNode->GetEventHub<EventHub>();
120     CHECK_NULL_VOID(eventHub);
121     OnAreaChangedFunc onAreaChangedFunc = [popupNodeWk = WeakPtr<FrameNode>(host)](const RectF& oldRect,
122                                               const OffsetF& oldOrigin, const RectF& /* rect */,
123                                               const OffsetF& /* origin */) {
124         auto popupNode = popupNodeWk.Upgrade();
125         CHECK_NULL_VOID(popupNode);
126         popupNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
127     };
128     eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
129 }
130 
OnDetachFromFrameNode(FrameNode * frameNode)131 void BubblePattern::OnDetachFromFrameNode(FrameNode* frameNode)
132 {
133     auto pipeline = PipelineContext::GetCurrentContext();
134     CHECK_NULL_VOID(pipeline);
135     pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
136     pipeline->RemoveWindowStateChangedCallback(frameNode->GetId());
137     auto targetNode = FrameNode::GetFrameNode(targetTag_, targetNodeId_);
138     CHECK_NULL_VOID(targetNode);
139     if (!hasOnAreaChange_) {
140         pipeline->RemoveOnAreaChangeNode(targetNode->GetId());
141     }
142 }
143 
InitTouchEvent()144 void BubblePattern::InitTouchEvent()
145 {
146     auto host = GetHost();
147     CHECK_NULL_VOID(host);
148     auto hub = host->GetEventHub<EventHub>();
149     CHECK_NULL_VOID(hub);
150     auto gestureHub = hub->GetOrCreateGestureEventHub();
151     CHECK_NULL_VOID(gestureHub);
152     if (touchEvent_) {
153         return;
154     }
155     auto touchTask = [weak = WeakClaim(this)](const TouchEventInfo& info) {
156         auto pattern = weak.Upgrade();
157         if (pattern) {
158             pattern->HandleTouchEvent(info);
159         }
160     };
161     touchEvent_ = MakeRefPtr<TouchEventImpl>(std::move(touchTask));
162     gestureHub->AddTouchEvent(touchEvent_);
163 }
164 
HandleTouchEvent(const TouchEventInfo & info)165 void BubblePattern::HandleTouchEvent(const TouchEventInfo& info)
166 {
167     if (info.GetTouches().empty()) {
168         return;
169     }
170     auto touchType = info.GetTouches().front().GetTouchType();
171     auto clickPos = info.GetTouches().front().GetLocalLocation();
172     if (touchType == TouchType::DOWN) {
173         HandleTouchDown(clickPos);
174     }
175 }
176 
HandleTouchDown(const Offset & clickPosition)177 void BubblePattern::HandleTouchDown(const Offset& clickPosition)
178 {
179     auto host = GetHost();
180     CHECK_NULL_VOID(host);
181     auto bubbleRenderProp = host->GetPaintProperty<BubbleRenderProperty>();
182     CHECK_NULL_VOID(bubbleRenderProp);
183     if (touchRegion_.IsInRegion(PointF(clickPosition.GetX(), clickPosition.GetY()))) {
184         return;
185     }
186     auto autoCancel = bubbleRenderProp->GetAutoCancel().value_or(true);
187     if (autoCancel) {
188         if (!GetInteractiveDismiss()) {
189             return;
190         }
191         if (HasOnWillDismiss()) {
192             auto pipelineNg = PipelineContext::GetCurrentContext();
193             CHECK_NULL_VOID(pipelineNg);
194             auto overlayManager = pipelineNg->GetOverlayManager();
195             CHECK_NULL_VOID(overlayManager);
196             overlayManager->SetDismissPopupId(targetNodeId_);
197             CallOnWillDismiss(static_cast<int32_t>(DismissReason::TOUCH_OUTSIDE));
198             return;
199         }
200         PopBubble();
201     }
202 }
203 
RegisterButtonOnHover()204 void BubblePattern::RegisterButtonOnHover()
205 {
206     if (mouseEventInitFlag_) {
207         return;
208     }
209     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
210     CHECK_NULL_VOID(paintProps);
211     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
212     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
213     auto custom = paintProps->GetUseCustom().value_or(false);
214     if (custom) {
215         return;
216     }
217     if (!primaryButtonShow && !secondaryButtonShow) {
218         return;
219     }
220     auto buttonRowNode = GetButtonRowNode();
221     for (const auto& child : buttonRowNode->GetChildren()) {
222         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
223         CHECK_NULL_VOID(buttonNode);
224         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
225             return;
226         }
227         auto inputHub = buttonNode->GetOrCreateInputEventHub();
228         CHECK_NULL_VOID(inputHub);
229         auto mouseTask = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
230             auto pattern = weak.Upgrade();
231             CHECK_NULL_VOID(pattern);
232             auto buttonNode = buttonNodeWK.Upgrade();
233             CHECK_NULL_VOID(buttonNode);
234             pattern->ButtonOnHover(isHover, buttonNode);
235         };
236         auto mouseEvent = MakeRefPtr<InputEvent>(std::move(mouseTask));
237         inputHub->AddOnHoverEvent(mouseEvent);
238     }
239     mouseEventInitFlag_ = true;
240 }
241 
ButtonOnHover(bool isHover,const RefPtr<NG::FrameNode> & buttonNode)242 void BubblePattern::ButtonOnHover(bool isHover, const RefPtr<NG::FrameNode>& buttonNode)
243 {
244     auto renderContext = buttonNode->GetRenderContext();
245     CHECK_NULL_VOID(renderContext);
246     auto pipeline = PipelineBase::GetCurrentContext();
247     CHECK_NULL_VOID(pipeline);
248     auto theme = pipeline->GetTheme<PopupTheme>();
249     isHover_ = isHover;
250     auto hoverColor = theme->GetButtonHoverColor();
251     auto backgroundColor = theme->GetButtonBackgroundColor();
252     if (isHover) {
253         // normal to hover
254         Animation(renderContext, hoverColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
255     } else {
256         // hover to normal
257         Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::FRICTION);
258     }
259 }
260 
RegisterButtonOnTouch()261 void BubblePattern::RegisterButtonOnTouch()
262 {
263     if (touchEventInitFlag_) {
264         return;
265     }
266     auto paintProps = GetPaintProperty<BubbleRenderProperty>();
267     CHECK_NULL_VOID(paintProps);
268     auto primaryButtonShow = paintProps->GetPrimaryButtonShow().value_or(false);
269     auto secondaryButtonShow = paintProps->GetSecondaryButtonShow().value_or(false);
270     auto custom = paintProps->GetUseCustom().value_or(false);
271     if (custom) {
272         return;
273     }
274     if (!primaryButtonShow && !secondaryButtonShow) {
275         return;
276     }
277 
278     auto buttonRowNode = GetButtonRowNode();
279     for (const auto& child : buttonRowNode->GetChildren()) {
280         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
281         CHECK_NULL_VOID(buttonNode);
282         if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
283             return;
284         }
285         auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
286         CHECK_NULL_VOID(gestureHub);
287         auto touchCallback = [weak = WeakClaim(this), buttonNodeWK = WeakPtr<FrameNode>(buttonNode)]
288             (const TouchEventInfo& info) {
289             auto pattern = weak.Upgrade();
290             CHECK_NULL_VOID(pattern);
291             auto buttonNode = buttonNodeWK.Upgrade();
292             CHECK_NULL_VOID(buttonNode);
293             pattern->ButtonOnPress(info, buttonNode);
294         };
295         auto touchEvent = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
296         gestureHub->AddTouchEvent(touchEvent);
297     }
298     touchEventInitFlag_ = true;
299 }
300 
ButtonOnPress(const TouchEventInfo & info,const RefPtr<NG::FrameNode> & buttonNode)301 void BubblePattern::ButtonOnPress(const TouchEventInfo& info, const RefPtr<NG::FrameNode>& buttonNode)
302 {
303     auto touchType = info.GetTouches().front().GetTouchType();
304     auto renderContext = buttonNode->GetRenderContext();
305     CHECK_NULL_VOID(renderContext);
306     auto pipeline = PipelineBase::GetCurrentContext();
307     CHECK_NULL_VOID(pipeline);
308     auto theme = pipeline->GetTheme<PopupTheme>();
309     CHECK_NULL_VOID(theme);
310     auto pressColor = theme->GetButtonPressColor();
311     auto hoverColor = theme->GetButtonHoverColor();
312     auto backgroundColor = theme->GetButtonBackgroundColor();
313     if (touchType == TouchType::DOWN) {
314         if (isHover_) {
315             // hover to press
316             Animation(renderContext, pressColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
317         } else {
318             // normal to press
319             Animation(renderContext, pressColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
320         }
321     } else if (touchType == TouchType::UP) {
322         if (isHover_) {
323             // press to hover
324             Animation(renderContext, hoverColor, theme->GetHoverToPressAnimationDuration(), Curves::SHARP);
325         } else {
326             // press to normal
327             Animation(renderContext, backgroundColor, theme->GetHoverAnimationDuration(), Curves::SHARP);
328         }
329     }
330 }
331 
GetButtonRowNode()332 RefPtr<FrameNode> BubblePattern::GetButtonRowNode()
333 {
334     auto host = GetHost();
335     CHECK_NULL_RETURN(host, nullptr);
336     auto columnNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
337     CHECK_NULL_RETURN(columnNode, nullptr);
338     auto lastColumnNode = AceType::DynamicCast<FrameNode>(columnNode->GetLastChild());
339     CHECK_NULL_RETURN(lastColumnNode, nullptr);
340     auto buttonRowNode = AceType::DynamicCast<FrameNode>(lastColumnNode->GetLastChild());
341     CHECK_NULL_RETURN(buttonRowNode, nullptr);
342     if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
343         if (buttonRowNode->GetTag() != V2::ROW_ETS_TAG) {
344             return nullptr;
345         }
346     } else {
347         if (buttonRowNode->GetTag() != V2::FLEX_ETS_TAG) {
348             return nullptr;
349         }
350     }
351     if (buttonRowNode->GetChildren().empty()) {
352         return nullptr;
353     }
354     return buttonRowNode;
355 }
356 
PopBubble()357 void BubblePattern::PopBubble()
358 {
359     auto pipelineNg = PipelineContext::GetCurrentContext();
360     CHECK_NULL_VOID(pipelineNg);
361     auto overlayManager = pipelineNg->GetOverlayManager();
362     CHECK_NULL_VOID(overlayManager);
363     auto popupInfo = overlayManager->GetPopupInfo(targetNodeId_);
364     if (!popupInfo.isCurrentOnShow) {
365         return;
366     }
367     popupInfo.markNeedUpdate = true;
368     auto host = GetHost();
369     CHECK_NULL_VOID(host);
370     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
371     CHECK_NULL_VOID(layoutProp);
372     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
373     if (showInSubWindow) {
374         SubwindowManager::GetInstance()->HidePopupNG(targetNodeId_);
375     } else {
376         overlayManager->HidePopup(targetNodeId_, popupInfo);
377     }
378 }
379 
GetPopupTheme()380 RefPtr<PopupTheme> BubblePattern::GetPopupTheme()
381 {
382     auto pipelineContext = PipelineBase::GetCurrentContext();
383     CHECK_NULL_RETURN(pipelineContext, nullptr);
384     auto popupTheme = pipelineContext->GetTheme<PopupTheme>();
385     CHECK_NULL_RETURN(popupTheme, nullptr);
386     return popupTheme;
387 }
388 
Animation(RefPtr<RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)389 void BubblePattern::Animation(
390     RefPtr<RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
391 {
392     AnimationOption option = AnimationOption();
393     option.SetCurve(curve);
394     option.SetDuration(duration);
395     option.SetFillMode(FillMode::FORWARDS);
396     AnimationUtils::Animate(
397         option, [buttonContext = renderContext, color = endColor]() { buttonContext->UpdateBackgroundColor(color); });
398 }
399 
PostTask(const TaskExecutor::Task & task,const std::string & name)400 bool BubblePattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
401 {
402     auto pipeline = PipelineBase::GetCurrentContext();
403     CHECK_NULL_RETURN(pipeline, false);
404     auto taskExecutor = pipeline->GetTaskExecutor();
405     CHECK_NULL_RETURN(taskExecutor, false);
406     return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
407 }
408 
StartEnteringTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)409 void BubblePattern::StartEnteringTransitionEffects(
410     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
411 {
412     auto popupId = popupNode->GetId();
413     auto pattern = popupNode->GetPattern<BubblePattern>();
414     pattern->transitionStatus_ = TransitionStatus::ENTERING;
415     auto layoutProp = popupNode->GetLayoutProperty<BubbleLayoutProperty>();
416     CHECK_NULL_VOID(layoutProp);
417     layoutProp->UpdateVisibility(VisibleType::VISIBLE, false);
418     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
419     auto isBlock = layoutProp->GetBlockEventValue(true);
420     auto& renderContext = popupNode->GetRenderContext();
421     renderContext->SetTransitionInCallback(
422         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
423             auto pattern = weak.Upgrade();
424             CHECK_NULL_VOID(pattern);
425             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
426                 return;
427             }
428             pattern->transitionStatus_ = TransitionStatus::NORMAL;
429             if (showInSubWindow) {
430                 std::vector<Rect> rects;
431                 if (!isBlock) {
432                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
433                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
434                     rects.emplace_back(rect);
435                 } else {
436                     auto parentWindowRect = SubwindowManager::GetInstance()->GetParentWindowRect();
437                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
438                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
439                     rects.emplace_back(parentWindowRect);
440                     rects.emplace_back(rect);
441                 }
442                 auto subWindowMgr = SubwindowManager::GetInstance();
443                 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
444             }
445             if (finish) {
446                 finish();
447             }
448         });
449 }
450 
StartExitingTransitionEffects(const RefPtr<FrameNode> & popupNode,const std::function<void ()> & finish)451 void BubblePattern::StartExitingTransitionEffects(
452     const RefPtr<FrameNode>& popupNode, const std::function<void()>& finish)
453 {
454     auto pattern = popupNode->GetPattern<BubblePattern>();
455     pattern->transitionStatus_ = TransitionStatus::EXITING;
456     auto layoutProperty = popupNode->GetLayoutProperty();
457     layoutProperty->UpdateVisibility(VisibleType::INVISIBLE, true);
458     auto renderContext = popupNode->GetRenderContext();
459     renderContext->SetTransitionOutCallback(
460         [weak = WeakClaim(this), finish]() {
461             auto pattern = weak.Upgrade();
462             CHECK_NULL_VOID(pattern);
463             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
464                 return;
465             }
466             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
467             if (finish) {
468                 finish();
469             }
470         });
471 }
472 
StartEnteringAnimation(std::function<void ()> finish)473 void BubblePattern::StartEnteringAnimation(std::function<void()> finish)
474 {
475     if (!arrowPlacement_.has_value()) {
476         delayShow_ = true;
477         finish_ = finish;
478         return;
479     }
480     if (IsOnShow()) {
481         return;
482     }
483 
484     if (transitionStatus_ == TransitionStatus::INVISIABLE) {
485         ResetToInvisible();
486     }
487 
488     StartOffsetEnteringAnimation();
489     if (finish) {
490         StartAlphaEnteringAnimation(finish);
491     } else {
492         StartAlphaEnteringAnimation(finish_);
493     }
494 }
495 
StartOffsetEnteringAnimation()496 void BubblePattern::StartOffsetEnteringAnimation()
497 {
498     AnimationOption optionPosition;
499     optionPosition.SetDuration(ENTRY_ANIMATION_DURATION);
500     optionPosition.SetCurve(Curves::FRICTION);
501     AnimationUtils::Animate(
502         optionPosition,
503         [weak = WeakClaim(this)]() {
504             auto pattern = weak.Upgrade();
505             CHECK_NULL_VOID(pattern);
506             auto renderContext = pattern->GetRenderContext();
507             CHECK_NULL_VOID(renderContext);
508             renderContext->UpdateOffset(OffsetT<Dimension>());
509             renderContext->SyncGeometryProperties(nullptr);
510         },
511         nullptr);
512 }
513 
StartAlphaEnteringAnimation(std::function<void ()> finish)514 void BubblePattern::StartAlphaEnteringAnimation(std::function<void()> finish)
515 {
516     AnimationOption optionAlpha;
517     optionAlpha.SetDuration(ENTRY_ANIMATION_DURATION);
518     optionAlpha.SetCurve(Curves::SHARP);
519     auto host = GetHost();
520     auto popupId = host->GetId();
521     CHECK_NULL_VOID(host);
522     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
523     CHECK_NULL_VOID(layoutProp);
524     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
525     auto isBlock = layoutProp->GetBlockEventValue(true);
526     AnimationUtils::Animate(
527         optionAlpha,
528         [weak = WeakClaim(this)]() {
529             auto pattern = weak.Upgrade();
530             CHECK_NULL_VOID(pattern);
531             pattern->transitionStatus_ = TransitionStatus::ENTERING;
532             auto renderContext = pattern->GetRenderContext();
533             CHECK_NULL_VOID(renderContext);
534             renderContext->UpdateOpacity(VISIABLE_ALPHA);
535         },
536         [weak = WeakClaim(this), finish, showInSubWindow, popupId, isBlock]() {
537             auto pattern = weak.Upgrade();
538             CHECK_NULL_VOID(pattern);
539             if (pattern->transitionStatus_ != TransitionStatus::ENTERING) {
540                 return;
541             }
542             pattern->transitionStatus_ = TransitionStatus::NORMAL;
543             if (showInSubWindow) {
544                 std::vector<Rect> rects;
545                 if (!isBlock) {
546                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
547                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
548                     rects.emplace_back(rect);
549                 } else {
550                     auto parentWindowRect = SubwindowManager::GetInstance()->GetParentWindowRect();
551                     auto rect = Rect(pattern->GetChildOffset().GetX(), pattern->GetChildOffset().GetY(),
552                         pattern->GetChildSize().Width(), pattern->GetChildSize().Height());
553                     rects.emplace_back(parentWindowRect);
554                     rects.emplace_back(rect);
555                 }
556                 auto subWindowMgr = SubwindowManager::GetInstance();
557                 subWindowMgr->SetHotAreas(rects, popupId, pattern->GetContainerId());
558             }
559             if (finish) {
560                 finish();
561             }
562         });
563 }
564 
StartExitingAnimation(std::function<void ()> finish)565 void BubblePattern::StartExitingAnimation(std::function<void()> finish)
566 {
567     StartOffsetExitingAnimation();
568     StartAlphaExitingAnimation(finish);
569 }
570 
StartOffsetExitingAnimation()571 void BubblePattern::StartOffsetExitingAnimation()
572 {
573     AnimationOption optionPosition;
574     optionPosition.SetDuration(EXIT_ANIMATION_DURATION);
575     optionPosition.SetCurve(Curves::FRICTION);
576     AnimationUtils::Animate(
577         optionPosition,
578         [weak = WeakClaim(this)]() {
579             auto pattern = weak.Upgrade();
580             CHECK_NULL_VOID(pattern);
581             auto renderContext = pattern->GetRenderContext();
582             CHECK_NULL_VOID(renderContext);
583             renderContext->UpdateOffset(pattern->GetInvisibleOffset());
584             renderContext->SyncGeometryProperties(nullptr);
585         },
586         nullptr);
587 }
588 
StartAlphaExitingAnimation(std::function<void ()> finish)589 void BubblePattern::StartAlphaExitingAnimation(std::function<void()> finish)
590 {
591     AnimationOption optionAlpha;
592     optionAlpha.SetDuration(EXIT_ANIMATION_DURATION);
593     optionAlpha.SetCurve(Curves::SHARP);
594     AnimationUtils::Animate(
595         optionAlpha,
596         [weak = WeakClaim(this)]() {
597             auto pattern = weak.Upgrade();
598             CHECK_NULL_VOID(pattern);
599             pattern->transitionStatus_ = TransitionStatus::EXITING;
600             auto renderContext = pattern->GetRenderContext();
601             CHECK_NULL_VOID(renderContext);
602             renderContext->UpdateOpacity(INVISIABLE_ALPHA);
603         },
604         [weak = WeakClaim(this), finish]() {
605             auto pattern = weak.Upgrade();
606             CHECK_NULL_VOID(pattern);
607             if (pattern->transitionStatus_ != TransitionStatus::EXITING) {
608                 return;
609             }
610             pattern->transitionStatus_ = TransitionStatus::INVISIABLE;
611             if (finish) {
612                 finish();
613             }
614         });
615 }
616 
IsOnShow()617 bool BubblePattern::IsOnShow()
618 {
619     return (transitionStatus_ == TransitionStatus::ENTERING) || (transitionStatus_ == TransitionStatus::NORMAL);
620 }
621 
IsExiting()622 bool BubblePattern::IsExiting()
623 {
624     return transitionStatus_ == TransitionStatus::EXITING;
625 }
626 
GetInvisibleOffset()627 OffsetT<Dimension> BubblePattern::GetInvisibleOffset()
628 {
629     if (!arrowPlacement_.has_value()) {
630         return OffsetT<Dimension>();
631     }
632 
633     OffsetT<Dimension> offset;
634     switch (arrowPlacement_.value()) {
635         case Placement::LEFT:
636         case Placement::LEFT_TOP:
637         case Placement::LEFT_BOTTOM:
638             offset.AddX(INVISIABLE_OFFSET);
639             break;
640         case Placement::RIGHT:
641         case Placement::RIGHT_TOP:
642         case Placement::RIGHT_BOTTOM:
643             offset.AddX(INVISIABLE_OFFSET * -1);
644             break;
645         case Placement::TOP:
646         case Placement::TOP_LEFT:
647         case Placement::TOP_RIGHT:
648             offset.AddY(INVISIABLE_OFFSET);
649             break;
650         case Placement::BOTTOM:
651         case Placement::BOTTOM_LEFT:
652         case Placement::BOTTOM_RIGHT:
653             offset.AddY(INVISIABLE_OFFSET * -1);
654             break;
655         default:
656             break;
657     }
658     return offset;
659 }
660 
GetRenderContext()661 RefPtr<RenderContext> BubblePattern::GetRenderContext()
662 {
663     auto frameNode = GetHost();
664     CHECK_NULL_RETURN(frameNode, nullptr);
665     return frameNode->GetRenderContext();
666 }
667 
ResetToInvisible()668 void BubblePattern::ResetToInvisible()
669 {
670     auto renderContext = GetRenderContext();
671     CHECK_NULL_VOID(renderContext);
672 
673     renderContext->UpdateOpacity(INVISIABLE_ALPHA);
674     renderContext->UpdateOffset(GetInvisibleOffset());
675     renderContext->SyncGeometryProperties(nullptr);
676 }
677 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)678 void BubblePattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
679 {
680     switch (type) {
681         case WindowSizeChangeReason::UNDEFINED:
682         case WindowSizeChangeReason::MOVE:
683         case WindowSizeChangeReason::RESIZE:
684         case WindowSizeChangeReason::DRAG_START:
685         case WindowSizeChangeReason::DRAG:
686         case WindowSizeChangeReason::DRAG_END: {
687             break;
688         }
689         default: {
690             auto pipelineNg = PipelineContext::GetCurrentContext();
691             CHECK_NULL_VOID(pipelineNg);
692             auto overlayManager = pipelineNg->GetOverlayManager();
693             CHECK_NULL_VOID(overlayManager);
694             overlayManager->HideAllPopups();
695             auto host = GetHost();
696             CHECK_NULL_VOID(host);
697             auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
698             CHECK_NULL_VOID(layoutProp);
699             auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
700             if (showInSubWindow) {
701                 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
702                 CHECK_NULL_VOID(subwindow);
703                 subwindow->HidePopupNG(targetNodeId_);
704             }
705         }
706     }
707 }
708 
OnWindowHide()709 void BubblePattern::OnWindowHide()
710 {
711     auto pipelineNg = PipelineContext::GetCurrentContext();
712     CHECK_NULL_VOID(pipelineNg);
713     auto overlayManager = pipelineNg->GetOverlayManager();
714     CHECK_NULL_VOID(overlayManager);
715     overlayManager->HideAllPopups();
716     auto host = GetHost();
717     CHECK_NULL_VOID(host);
718     auto layoutProp = host->GetLayoutProperty<BubbleLayoutProperty>();
719     CHECK_NULL_VOID(layoutProp);
720     auto showInSubWindow = layoutProp->GetShowInSubWindow().value_or(false);
721     if (showInSubWindow) {
722         auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(Container::CurrentId());
723         CHECK_NULL_VOID(subwindow);
724         subwindow->HidePopupNG(targetNodeId_);
725     }
726 }
727 
728 
UpdateText(const RefPtr<UINode> & node,const RefPtr<PopupTheme> & popupTheme)729 void BubblePattern::UpdateText(const RefPtr<UINode>& node, const RefPtr<PopupTheme>& popupTheme)
730 {
731     if (node->GetTag() == V2::TEXT_ETS_TAG) {
732         auto textNode = DynamicCast<FrameNode>(node);
733         CHECK_NULL_VOID(textNode);
734         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
735         CHECK_NULL_VOID(textLayoutProperty);
736         auto parentNode = node->GetParent();
737         if (parentNode && parentNode->GetTag() == V2::BUTTON_ETS_TAG &&
738             !(Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
739             textLayoutProperty->UpdateTextColor(popupTheme->GetButtonFontColor());
740         } else if (!isSetMessageColor_) {
741             if ((Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN))) {
742                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontColor());
743             } else {
744                 textLayoutProperty->UpdateTextColor(popupTheme->GetFontPrimaryColor());
745             }
746         }
747         textNode->MarkModifyDone();
748     } else {
749         for (const auto& childNode : node->GetChildren()) {
750             UpdateText(childNode, popupTheme);
751         }
752     }
753 }
754 
UpdateBubbleText()755 void BubblePattern::UpdateBubbleText()
756 {
757     auto host = GetHost();
758     CHECK_NULL_VOID(host);
759     host->SetNeedCallChildrenUpdate(false);
760     auto context = host->GetContext();
761     CHECK_NULL_VOID(context);
762     auto popupTheme = context->GetTheme<PopupTheme>();
763     CHECK_NULL_VOID(popupTheme);
764     UpdateText(host, popupTheme);
765     host->MarkDirtyNode();
766 }
767 
OnColorConfigurationUpdate()768 void BubblePattern::OnColorConfigurationUpdate()
769 {
770     if (isCustomPopup_) {
771         return;
772     }
773     colorMode_ = SystemProperties::GetColorMode();
774     UpdateBubbleText();
775 }
776 
UpdateAgingTextSize()777 void BubblePattern::UpdateAgingTextSize()
778 {
779     if (isCustomPopup_) {
780         return;
781     }
782     CHECK_NULL_VOID(messageNode_);
783     messageNode_->MarkDirtyNode();
784 }
785 } // namespace OHOS::Ace::NG
786