• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_ng/pattern/navrouter/navdestination_group_node.h"
17 
18 #include "core/common/force_split/force_split_utils.h"
19 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
20 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
21 #include "core/components_ng/pattern/navigation/navigation_transition_proxy.h"
22 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
23 #include "core/components_ng/pattern/text/text_pattern.h"
24 #include "core/components_v2/inspector/inspector_constants.h"
25 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.h"
26 
27 namespace OHOS::Ace::NG {
28 constexpr double HALF = 0.5;
29 constexpr float TITLE_OFFSET_PERCENT = 0.02f;
30 constexpr int32_t OPACITY_TITLE_OUT_DELAY = 17;
31 constexpr int32_t OPACITY_TITLE_IN_DELAY = 33;
32 constexpr int32_t OPACITY_TITLE_DURATION = 150;
33 constexpr int32_t OPACITY_BACKBUTTON_IN_DELAY = 150;
34 constexpr int32_t OPACITY_BACKBUTTON_IN_DURATION = 200;
35 constexpr int32_t OPACITY_BACKBUTTON_OUT_DURATION = 67;
36 constexpr int32_t MAX_RENDER_GROUP_TEXT_NODE_COUNT = 50;
37 constexpr float MAX_RENDER_GROUP_TEXT_NODE_HEIGHT = 150.0f;
38 constexpr int32_t INVALID_ANIMATION_ID = -1;
39 constexpr int32_t SYSTEM_ENTER_FADE_TRANSITION_DURATION = 250;
40 constexpr int32_t SYSTEM_EXIT_FADE_TRANSITION_DURATION = 200;
41 constexpr int32_t SYSTEM_ENTER_FADE_TRANSITION_DELAY = 50;
42 constexpr int32_t SYSTEM_EXIT_FADE_TRANSITION_DELAY = 0;
43 constexpr int32_t SYSTEM_EXPLODE_TRANSITION_MASK_DURATION = 300;
44 constexpr int32_t SYSTEM_ENTER_POP_EXPLODE_OPACITY_DURATION = 250;
45 constexpr int32_t SYSTEM_ENTER_POP_EXPLODE_OPACITY_DELAY = 50;
46 constexpr int32_t SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DURATION = 300;
47 constexpr int32_t SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DELAY = 50;
48 constexpr int32_t SYSTEM_EXIT_POP_EXPLODE_OPACITY_DURATION = 150;
49 constexpr int32_t SYSTEM_EXIT_PUSH_EXPLODE_OPACITY_DELAY = 200;
50 constexpr int32_t SYSTEM_SLIDE_TRANSITION_MASK_DURATION = 350;
51 const Color SLIDE_ANIMATION_MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
52 
53 namespace {
TransitionTypeToString(NavigationSystemTransitionType type)54 const char* TransitionTypeToString(NavigationSystemTransitionType type)
55 {
56     switch (type) {
57         case NavigationSystemTransitionType::NONE:
58             return "NavigationSystemTransitionType.NONE";
59         case NavigationSystemTransitionType::TITLE:
60             return "NavigationSystemTransitionType.TITLE";
61         case NavigationSystemTransitionType::CONTENT:
62             return "NavigationSystemTransitionType.CONTENT";
63         case NavigationSystemTransitionType::FADE:
64             return "NavigationSystemTransitionType.FADE";
65         case NavigationSystemTransitionType::EXPLODE:
66             return "NavigationSystemTransitionType.EXPLODE";
67         case NavigationSystemTransitionType::SLIDE_RIGHT:
68             return "NavigationSystemTransitionType.SLIDE_RIGHT";
69         case NavigationSystemTransitionType::SLIDE_BOTTOM:
70             return "NavigationSystemTransitionType.SLIDE_BOTTOM";
71         default:
72             return "NavigationSystemTransitionType.DEFAULT";
73     }
74 }
75 
BuildAnimationOption(const RefPtr<Curve> & curve,std::function<void ()> && onFinishEvent,int32_t duration=0,int32_t delay=0)76 AnimationOption BuildAnimationOption(const RefPtr<Curve>& curve, std::function<void()>&& onFinishEvent,
77     int32_t duration = 0, int32_t delay = 0)
78 {
79     AnimationOption option(curve, duration);
80     option.SetDelay(delay);
81     option.SetOnFinishEvent(std::move(onFinishEvent));
82     return option;
83 }
84 }
85 
~NavDestinationGroupNode()86 NavDestinationGroupNode::~NavDestinationGroupNode()
87 {
88     if (contentNode_) {
89         contentNode_->Clean();
90     }
91     ReleaseTextNodeList();
92 }
93 
GetOrCreateGroupNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)94 RefPtr<NavDestinationGroupNode> NavDestinationGroupNode::GetOrCreateGroupNode(
95     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
96 {
97     auto frameNode = GetFrameNode(tag, nodeId);
98     CHECK_NULL_RETURN(!frameNode, AceType::DynamicCast<NavDestinationGroupNode>(frameNode));
99     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
100     auto navDestinationNode = AceType::MakeRefPtr<NavDestinationGroupNode>(tag, nodeId, pattern);
101     CHECK_NULL_RETURN(navDestinationNode, nullptr);
102     navDestinationNode->InitializePatternAndContext();
103     ElementRegister::GetInstance()->AddUINode(navDestinationNode);
104     return navDestinationNode;
105 }
106 
IsNeedContentTransition()107 bool NavDestinationGroupNode::IsNeedContentTransition()
108 {
109     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
110         // for HomeNavDestination, DEFAULT equals to NONE when split mode.
111         if (!isHomeDestination_) {
112             return true;
113         }
114         auto navNode = AceType::DynamicCast<NavigationGroupNode>(GetNavigationNode());
115         CHECK_NULL_RETURN(navNode, true);
116         auto pattern = navNode->GetPattern<NavigationPattern>();
117         CHECK_NULL_RETURN(pattern, true);
118         return pattern->GetNavigationMode() == NavigationMode::STACK;
119     }
120     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
121 }
122 
TransitionContentInValid()123 bool NavDestinationGroupNode::TransitionContentInValid()
124 {
125     if (isHomeDestination_) {
126         auto navNode = AceType::DynamicCast<NavigationGroupNode>(GetNavigationNode());
127         CHECK_NULL_RETURN(navNode, false);
128         auto navPattern = navNode->GetPattern<NavigationPattern>();
129         CHECK_NULL_RETURN(navPattern, false);
130         auto mode = navPattern->GetNavigationMode();
131         return mode == NavigationMode::SPLIT;
132     }
133     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) == NavigationSystemTransitionType::NONE
134         && mode_ == NavDestinationMode::STANDARD;
135 }
136 
IsNeedTitleTransition()137 bool NavDestinationGroupNode::IsNeedTitleTransition()
138 {
139     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
140         // for HomeNavDestination, DEFAULT equals to NONE when split mode.
141         if (!isHomeDestination_) {
142             return true;
143         }
144         auto navNode = AceType::DynamicCast<NavigationGroupNode>(GetNavigationNode());
145         CHECK_NULL_RETURN(navNode, true);
146         auto pattern = navNode->GetPattern<NavigationPattern>();
147         CHECK_NULL_RETURN(pattern, true);
148         return pattern->GetNavigationMode() == NavigationMode::STACK;
149     }
150     if (mode_ == NavDestinationMode::STANDARD) {
151         return (systemTransitionType_ & NavigationSystemTransitionType::TITLE) != NavigationSystemTransitionType::NONE;
152     }
153     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
154 }
155 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)156 void NavDestinationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
157 {
158     auto pattern = AceType::DynamicCast<Pattern>(GetPattern());
159     CHECK_NULL_VOID(pattern);
160     auto contentNode = GetContentNode();
161     if (!contentNode) {
162         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
163         ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId);
164         contentNode = FrameNode::GetOrCreateFrameNode(V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId,
165             []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
166         SetContentNode(contentNode);
167         AddChild(contentNode);
168 
169         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
170             auto navdestinationContentNode = AceType::DynamicCast<FrameNode>(contentNode);
171             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
172                 .edges = SAFE_AREA_EDGE_ALL };
173             navdestinationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
174         }
175     }
176     contentNode->AddChild(child, slot);
177 }
178 
DeleteChildFromGroup(int32_t slot)179 void NavDestinationGroupNode::DeleteChildFromGroup(int32_t slot)
180 {
181     auto navDestination = GetContentNode();
182     CHECK_NULL_VOID(navDestination);
183     navDestination->RemoveChildAtIndex(slot);
184 }
185 
OnAttachToMainTree(bool recursive)186 void NavDestinationGroupNode::OnAttachToMainTree(bool recursive)
187 {
188     if (!UseOffscreenProcess()) {
189         ProcessShallowBuilder();
190     }
191     FrameNode::OnAttachToMainTree(recursive);
192     SetFreeze(false, true);
193 }
194 
OnOffscreenProcess(bool recursive)195 void NavDestinationGroupNode::OnOffscreenProcess(bool recursive)
196 {
197     ProcessShallowBuilder();
198     FrameNode::OnOffscreenProcess(recursive);
199 }
200 
ProcessShallowBuilder()201 void NavDestinationGroupNode::ProcessShallowBuilder()
202 {
203     if (isCacheNode_) {
204         return;
205     }
206 
207     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "render navDestination content");
208     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
209     CHECK_NULL_VOID(navDestinationPattern);
210     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
211     if (shallowBuilder && !shallowBuilder->IsExecuteDeepRenderDone()) {
212         auto eventHub = GetOrCreateEventHub<NavDestinationEventHub>();
213         if (eventHub) {
214             auto ctx = navDestinationPattern->GetNavDestinationContext();
215             eventHub->FireOnReady(ctx);
216         }
217         shallowBuilder->ExecuteDeepRender();
218         GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
219         AceType::DynamicCast<FrameNode>(contentNode_)
220             ->GetLayoutProperty()
221             ->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
222     }
223 }
224 
GetNavDestinationCustomNode()225 RefPtr<CustomNodeBase> NavDestinationGroupNode::GetNavDestinationCustomNode()
226 {
227     return customNode_.Upgrade();
228 }
229 
GetNavigationNodeId() const230 int32_t NavDestinationGroupNode::GetNavigationNodeId() const
231 {
232     auto pattern = AceType::DynamicCast<NavDestinationPattern>(GetPattern());
233     CHECK_NULL_RETURN(pattern, DEFAULT_NODE_SLOT);
234     auto navigationNode = pattern->GetNavigationNode();
235     CHECK_NULL_RETURN(navigationNode, DEFAULT_NODE_SLOT);
236     return navigationNode->GetId();
237 }
238 
SetNavDestinationMode(NavDestinationMode mode)239 void NavDestinationGroupNode::SetNavDestinationMode(NavDestinationMode mode)
240 {
241     mode_ = mode;
242     auto pattern = GetPattern<NavDestinationPattern>();
243     CHECK_NULL_VOID(pattern);
244     auto context = pattern->GetNavDestinationContext();
245     CHECK_NULL_VOID(context);
246     context->SetMode(mode);
247 }
248 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const249 void NavDestinationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
250 {
251     FrameNode::ToJsonValue(json, filter);
252     /* no fixed attr below, just return */
253     if (filter.IsFastFilter()) {
254         return;
255     }
256     auto titleBarNode = DynamicCast<TitleBarNode>(titleBarNode_);
257     if (titleBarNode) {
258         std::string title = NavigationTitleUtil::GetTitleString(titleBarNode, GetPrevTitleIsCustomValue(false));
259         std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
260         json->PutExtAttr("title", title.c_str(), filter);
261         json->PutExtAttr("subtitle", subtitle.c_str(), filter);
262     }
263     auto navBarPattern = GetPattern<NavDestinationPatternBase>();
264     if (navBarPattern) {
265         auto menuOptionsJson = JsonUtil::Create(true);
266         auto moreButtonOptions = navBarPattern->GetMenuOptions();
267         moreButtonOptions.ToJsonValue(menuOptionsJson, filter);
268         json->PutExtAttr("menuOptions", menuOptionsJson, filter);
269     }
270     json->PutExtAttr("mode", mode_ == NavDestinationMode::DIALOG
271         ? "NavDestinationMode::DIALOG"
272         : "NavDestinationMode::STANDARD", filter);
273     json->PutExtAttr("systemTransition", TransitionTypeToString(systemTransitionType_), filter);
274 }
275 
SystemTransitionPushStart(bool transitionIn)276 void NavDestinationGroupNode::SystemTransitionPushStart(bool transitionIn)
277 {
278     if (destType_ == NavDestinationType::HOME) {
279         return;
280     }
281     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
282     float isRTL = GetLanguageDirection();
283     bool needContentAnimation = IsNeedContentTransition();
284     bool needTitleAnimation = IsNeedTitleTransition();
285     auto renderContext = GetRenderContext();
286     CHECK_NULL_VOID(renderContext);
287     auto geometryNode = GetGeometryNode();
288     CHECK_NULL_VOID(geometryNode);
289     auto frameSize = geometryNode->GetFrameSize();
290     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
291     if (transitionIn) {
292         SetIsOnAnimation(true);
293         SetTransitionType(PageTransitionType::ENTER_PUSH);
294         if (needContentAnimation) {
295             RectF rect = CalcHalfClipRectForTransition(frameSizeWithSafeArea);
296             renderContext->ClipWithRRect(rect, RadiusF(EdgeF(0.0f, 0.0f)));
297             auto translate = CalcTranslateForTransitionPushStart(frameSizeWithSafeArea, true);
298             renderContext->UpdateTranslateInXY(translate);
299         }
300         if (titleBarNode && needTitleAnimation) {
301             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
302         }
303         return;
304     }
305     SetTransitionType(PageTransitionType::EXIT_PUSH);
306     SetIsOnAnimation(true);
307     renderContext->RemoveClipWithRRect();
308     if (needContentAnimation) {
309         auto translate = CalcTranslateForTransitionPushStart(frameSize, false);
310         renderContext->UpdateTranslateInXY(translate);
311     }
312     if (NeedRemoveInPush()) {
313         GetOrCreateEventHub<EventHub>()->SetEnabledInternal(false);
314     }
315     if (titleBarNode && needTitleAnimation) {
316         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
317     }
318 }
319 
InitSoftTransitionPush(bool transitionIn)320 void NavDestinationGroupNode::InitSoftTransitionPush(bool transitionIn)
321 {
322     if (destType_ == NavDestinationType::HOME) {
323         return;
324     }
325     bool needContentAnimation = IsNeedContentTransition();
326     auto renderContext = GetRenderContext();
327     CHECK_NULL_VOID(renderContext);
328     auto geometryNode = GetGeometryNode();
329     CHECK_NULL_VOID(geometryNode);
330     auto frameSize = geometryNode->GetFrameSize();
331     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
332     if (transitionIn) {
333         SetIsOnAnimation(true);
334         SetTransitionType(PageTransitionType::ENTER_PUSH);
335         auto translate = CalcTranslateForTransitionPushStart(frameSizeWithSafeArea, true);
336         if (needContentAnimation) {
337             renderContext->UpdateTranslateInXY(translate);
338         }
339         return;
340     }
341     SetTransitionType(PageTransitionType::EXIT_PUSH);
342     SetIsOnAnimation(true);
343     auto translate = CalcTranslateForTransitionPushStart(frameSize, false);
344     if (needContentAnimation) {
345         renderContext->UpdateTranslateInXY(translate);
346     }
347     if (NeedRemoveInPush()) {
348         GetEventHub<EventHub>()->SetEnabledInternal(false);
349     }
350 }
351 
StartSoftTransitionPush(bool transitionIn)352 void NavDestinationGroupNode::StartSoftTransitionPush(bool transitionIn)
353 {
354     if (destType_ == NavDestinationType::HOME) {
355         return;
356     }
357     auto geometryNode = GetGeometryNode();
358     CHECK_NULL_VOID(geometryNode);
359     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
360     bool needContentAnimation = IsNeedContentTransition();
361     auto renderContext = GetRenderContext();
362     CHECK_NULL_VOID(renderContext);
363     if (transitionIn) {
364         auto translate = CalcTranslateForTransitionPushEnd(frameSizeWithSafeArea, true);
365         if (needContentAnimation) {
366             renderContext->UpdateTranslateInXY(translate);
367         }
368         return;
369     }
370     auto translate = CalcTranslateForTransitionPushEnd(frameSizeWithSafeArea, false);
371     if (needContentAnimation) {
372         renderContext->UpdateTranslateInXY(translate);
373     }
374 }
375 
InitSoftTransitionPop(bool isTransitionIn)376 void NavDestinationGroupNode::InitSoftTransitionPop(bool isTransitionIn)
377 {
378     if (destType_ == NavDestinationType::HOME) {
379         return;
380     }
381     auto geometryNode = GetGeometryNode();
382     CHECK_NULL_VOID(geometryNode);
383     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
384     bool needContentAnimation = IsNeedContentTransition();
385     auto renderContext = GetRenderContext();
386     CHECK_NULL_VOID(renderContext);
387     if (isTransitionIn) {
388         SetTransitionType(PageTransitionType::ENTER_POP);
389         auto translate = CalcTranslateForTransitionPopStart(frameSizeWithSafeArea, true);
390         if (needContentAnimation) {
391             renderContext->UpdateTranslateInXY(translate);
392         }
393         return;
394     }
395     SetIsOnAnimation(true);
396     SetTransitionType(PageTransitionType::EXIT_POP);
397     GetEventHub<EventHub>()->SetEnabledInternal(false);
398     auto translate = CalcTranslateForTransitionPopStart(frameSizeWithSafeArea, false);
399     if (needContentAnimation) {
400         renderContext->UpdateTranslateInXY(translate);
401     }
402 }
403 
StartSoftTransitionPop(bool transitionIn)404 void NavDestinationGroupNode::StartSoftTransitionPop(bool transitionIn)
405 {
406     if (destType_ == NavDestinationType::HOME) {
407         return;
408     }
409     bool needContentAnimation = IsNeedContentTransition();
410     auto renderContext = GetRenderContext();
411     CHECK_NULL_VOID(renderContext);
412     auto geometryNode = GetGeometryNode();
413     CHECK_NULL_VOID(geometryNode);
414     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
415     if (transitionIn) {
416         auto translate = CalcTranslateForTransitionPopEnd(frameSizeWithSafeArea, true);
417         if (needContentAnimation) {
418             renderContext->UpdateTranslateInXY(translate);
419         }
420         return;
421     }
422     auto translate = CalcTranslateForTransitionPopEnd(frameSizeWithSafeArea, false);
423     if (needContentAnimation) {
424         renderContext->UpdateTranslateInXY(translate);
425     }
426 }
427 
SystemTransitionPushEnd(bool transitionIn)428 void NavDestinationGroupNode::SystemTransitionPushEnd(bool transitionIn)
429 {
430     if (destType_ == NavDestinationType::HOME) {
431         return;
432     }
433     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
434     auto geometryNode = GetGeometryNode();
435     CHECK_NULL_VOID(geometryNode);
436     auto frameSize = geometryNode->GetFrameSize();
437     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
438     float isRTL = GetLanguageDirection();
439     bool needContentAnimation = IsNeedContentTransition();
440     bool needTitleAnimation = IsNeedTitleTransition();
441     auto renderContext = GetRenderContext();
442     CHECK_NULL_VOID(renderContext);
443     if (transitionIn) {
444         if (needContentAnimation) {
445             RectF rect = CalcFullClipRectForTransition(frameSizeWithSafeArea);
446             renderContext->ClipWithRRect(rect, RadiusF(EdgeF(0.0f, 0.0f)));
447             auto translate = CalcTranslateForTransitionPushEnd(frameSizeWithSafeArea, true);
448             renderContext->UpdateTranslateInXY(translate);
449         }
450         if (titleBarNode && needTitleAnimation) {
451             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
452         }
453         return;
454     }
455     if (needContentAnimation) {
456         auto translate = CalcTranslateForTransitionPushEnd(frameSizeWithSafeArea, false);
457         renderContext->UpdateTranslateInXY(translate);
458     }
459     if (titleBarNode && needTitleAnimation) {
460         titleBarNode->GetRenderContext()->UpdateTranslateInXY(
461             { frameSize.Width() * TITLE_OFFSET_PERCENT  * isRTL, 0.0f });
462     }
463 }
464 
SystemTransitionPushFinish(bool transitionIn,int32_t animationId)465 void NavDestinationGroupNode::SystemTransitionPushFinish(bool transitionIn, int32_t animationId)
466 {
467     if (destType_ == NavDestinationType::HOME) {
468         return;
469     }
470     if (animationId != animationId_) {
471         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "push animation invalid,curId: %{public}d, targetId: %{public}d",
472             animationId_, animationId);
473         return;
474     }
475     SetIsOnAnimation(false);
476     if (transitionIn) {
477         if (GetTransitionType() != PageTransitionType::ENTER_PUSH) {
478             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "curNode has another transition");
479             return;
480         }
481         GetRenderContext()->RemoveClipWithRRect();
482         return;
483     }
484     if (IsNeedContentTransition()) {
485         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
486     }
487     GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
488     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
489     CHECK_NULL_VOID(navDestinationPattern);
490     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
491     CHECK_NULL_VOID(navigation);
492     bool isInvisible = IsNodeInvisible(navigation);
493     if (GetTransitionType() == PageTransitionType::EXIT_PUSH && isInvisible) {
494         GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
495         SetJSViewActive(false);
496     }
497     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
498     if (titleBarNode && IsNeedTitleTransition()) {
499         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
500     }
501 }
502 
SystemTransitionPopStart(bool transitionIn)503 void NavDestinationGroupNode::SystemTransitionPopStart(bool transitionIn)
504 {
505     if (destType_ == NavDestinationType::HOME) {
506         return;
507     }
508     auto geometryNode = GetGeometryNode();
509     CHECK_NULL_VOID(geometryNode);
510     auto frameSize = geometryNode->GetFrameSize();
511     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
512     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
513     float isRTL = GetLanguageDirection();
514     bool needContentAnimation = IsNeedContentTransition();
515     bool needTitleAnimation = IsNeedTitleTransition();
516     auto renderContext = GetRenderContext();
517     CHECK_NULL_VOID(renderContext);
518     if (transitionIn) {
519         SetTransitionType(PageTransitionType::ENTER_POP);
520         renderContext->RemoveClipWithRRect();
521         if (needContentAnimation) {
522             auto translate = CalcTranslateForTransitionPopStart(frameSizeWithSafeArea, true);
523             renderContext->UpdateTranslateInXY(translate);
524         }
525         if (titleBarNode && needTitleAnimation) {
526             titleBarNode->GetRenderContext()->UpdateTranslateInXY(
527                 { frameSize.Width() * TITLE_OFFSET_PERCENT * isRTL, 0.0f });
528         }
529         return;
530     }
531     SetIsOnAnimation(true);
532     SetTransitionType(PageTransitionType::EXIT_POP);
533     GetOrCreateEventHub<EventHub>()->SetEnabledInternal(false);
534     if (needContentAnimation) {
535         RectF rect = CalcFullClipRectForTransition(frameSizeWithSafeArea);
536         renderContext->ClipWithRRect(rect, RadiusF(EdgeF(0.0f, 0.0f)));
537         auto translate = CalcTranslateForTransitionPopStart(frameSizeWithSafeArea, false);
538         renderContext->UpdateTranslateInXY(translate);
539     }
540     if (titleBarNode && needTitleAnimation) {
541         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
542     }
543 }
544 
SystemTransitionPopEnd(bool transitionIn)545 void NavDestinationGroupNode::SystemTransitionPopEnd(bool transitionIn)
546 {
547     if (destType_ == NavDestinationType::HOME) {
548         return;
549     }
550     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
551     bool needContentAnimation = IsNeedContentTransition();
552     bool needTitleAnimation = IsNeedTitleTransition();
553     auto renderContext = GetRenderContext();
554     CHECK_NULL_VOID(renderContext);
555     auto geometryNode = GetGeometryNode();
556     CHECK_NULL_VOID(geometryNode);
557     auto frameSize = geometryNode->GetFrameSize();
558     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
559     if (transitionIn) {
560         if (needContentAnimation) {
561             auto translate = CalcTranslateForTransitionPopEnd(frameSizeWithSafeArea, true);
562             renderContext->UpdateTranslateInXY(translate);
563         }
564         if (titleBarNode && needTitleAnimation) {
565             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
566         }
567         return;
568     }
569     float isRTL = GetLanguageDirection();
570     if (needContentAnimation) {
571         RectF rect = CalcHalfClipRectForTransition(frameSizeWithSafeArea);
572         renderContext->ClipWithRRect(rect, RadiusF(EdgeF(0.0f, 0.0f)));
573         auto translate = CalcTranslateForTransitionPopEnd(frameSizeWithSafeArea, false);
574         renderContext->UpdateTranslateInXY(translate);
575     }
576     if (titleBarNode && needTitleAnimation) {
577         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
578     }
579 }
580 
CheckTransitionPop(const int32_t animationId)581 bool NavDestinationGroupNode::CheckTransitionPop(const int32_t animationId)
582 {
583     if (IsCacheNode()) {
584         return false;
585     }
586     if (animationId_ != animationId) {
587         return false;
588     }
589     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
590         return false;
591     }
592     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
593     CHECK_NULL_RETURN(preNavDesPattern, false);
594     return true;
595 }
596 
SystemTransitionPopFinish(int32_t animationId,bool isNeedCleanContent)597 bool NavDestinationGroupNode::SystemTransitionPopFinish(int32_t animationId, bool isNeedCleanContent)
598 {
599     if (destType_ == NavDestinationType::HOME) {
600         return true;
601     }
602     if (animationId_ != animationId) {
603         TAG_LOGW(AceLogTag::ACE_NAVIGATION,
604             "animation id is invalid, curId: %{public}d, targetId: %{public}d",
605             animationId_, animationId);
606         return false;
607     }
608     SetIsOnAnimation(false);
609     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
610         // has another transition, just return
611         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "preNavDesNode has another transition");
612         return false;
613     }
614     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
615     CHECK_NULL_RETURN(preNavDesPattern, false);
616 
617     // NavRouter will restore the preNavDesNode and needs to set the initial state after the animation ends.
618     if (isNeedCleanContent) {
619         CleanContent();
620     }
621     GetOrCreateEventHub<EventHub>()->SetEnabledInternal(true);
622     GetRenderContext()->RemoveClipWithRRect();
623     if (IsNeedContentTransition()) {
624         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
625     }
626     auto preTitleNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
627     if (preTitleNode && IsNeedTitleTransition()) {
628         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
629         preTitleNode->GetRenderContext()->SetOpacity(1.0);
630         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(preTitleNode);
631         CHECK_NULL_RETURN(titleBarNode, true);
632         auto preBackIcon = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
633         if (preBackIcon)  {
634             preBackIcon->GetRenderContext()->SetOpacity(1.0);
635         }
636     }
637     return true;
638 }
639 
InitDialogTransition(bool isZeroY)640 void NavDestinationGroupNode::InitDialogTransition(bool isZeroY)
641 {
642     if (destType_ == NavDestinationType::HOME) {
643         return;
644     }
645     if (systemTransitionType_ == NavigationSystemTransitionType::NONE
646         || systemTransitionType_ == NavigationSystemTransitionType::TITLE) {
647         return;
648     }
649     auto geometryNode = GetGeometryNode();
650     CHECK_NULL_VOID(geometryNode);
651     auto frameSizeWithSafeArea = geometryNode->GetFrameSize(true);
652     auto contentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
653     CHECK_NULL_VOID(contentNode);
654     auto context = contentNode->GetRenderContext();
655     CHECK_NULL_VOID(context);
656     if (isZeroY) {
657         context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
658         return;
659     }
660     auto translateOpts = CalcContentTranslateForDialog(frameSizeWithSafeArea);
661     context->UpdateTransformTranslate(translateOpts);
662 }
663 
TitleOpacityAnimation(bool isTransitionIn)664 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::TitleOpacityAnimation(bool isTransitionIn)
665 {
666     if (destType_ == NavDestinationType::HOME) {
667         return nullptr;
668     }
669     if (!IsNeedTitleTransition()) {
670         return nullptr;
671     }
672     CHECK_NULL_RETURN(GetTitleBarNode(), nullptr);
673     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
674     CHECK_NULL_RETURN(titleNode, nullptr);
675     auto titleRenderContext = titleNode->GetRenderContext();
676     CHECK_NULL_RETURN(titleRenderContext, nullptr);
677     AnimationOption opacityOption;
678     opacityOption.SetCurve(Curves::SHARP);
679     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
680     if (isTransitionIn) {
681         opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
682         titleRenderContext->SetOpacity(0.0f);
683         return AnimationUtils::StartAnimation(opacityOption,
684             [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
685             auto renderContext = weakRender.Upgrade();
686             CHECK_NULL_VOID(renderContext);
687             renderContext->SetOpacity(1.0f);
688         }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, GetContextRefPtr());
689     }
690     // recover after transition animation.
691     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
692     titleRenderContext->SetOpacity(1.0f);
693     return AnimationUtils::StartAnimation(opacityOption,
694         [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
695         auto renderContext = weakRender.Upgrade();
696         CHECK_NULL_VOID(renderContext);
697         renderContext->SetOpacity(0.0f);
698     }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, GetContextRefPtr());
699 }
700 
BackButtonAnimation(bool isTransitionIn)701 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::BackButtonAnimation(bool isTransitionIn)
702 {
703     if (destType_ == NavDestinationType::HOME) {
704         return nullptr;
705     }
706     if (!IsNeedTitleTransition()) {
707         return nullptr;
708     }
709     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
710     CHECK_NULL_RETURN(titleNode, nullptr);
711     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetCustomBackButton());
712     if (!backButtonNode) {
713         backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
714     }
715     CHECK_NULL_RETURN(backButtonNode, nullptr);
716     AnimationOption transitionOption;
717     transitionOption.SetCurve(Curves::SHARP);
718     auto backButtonNodeContext = backButtonNode->GetRenderContext();
719     CHECK_NULL_RETURN(backButtonNodeContext, nullptr);
720     if (isTransitionIn) {
721         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
722         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
723         backButtonNodeContext->SetOpacity(0.0f);
724         return AnimationUtils::StartAnimation(transitionOption,
725             [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
726             auto renderContext = weakRender.Upgrade();
727             CHECK_NULL_VOID(renderContext);
728             renderContext->SetOpacity(1.0f);
729         }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, GetContextRefPtr());
730     }
731     transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
732     backButtonNodeContext->SetOpacity(1.0f);
733     return AnimationUtils::StartAnimation(transitionOption,
734         [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
735         auto renderContext = weakRender.Upgrade();
736         CHECK_NULL_VOID(renderContext);
737         renderContext->SetOpacity(0.0f);
738     }, nullptr /* finishCallback*/, nullptr /* repeatCallback */, GetContextRefPtr());
739 }
740 
UpdateTextNodeListAsRenderGroup(bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy)741 void NavDestinationGroupNode::UpdateTextNodeListAsRenderGroup(
742     bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy)
743 {
744     if (isPopPage) {
745         CollectTextNodeAsRenderGroup(isPopPage);
746     } else {
747         CHECK_NULL_VOID(proxy);
748         auto pipeline = PipelineContext::GetCurrentContext();
749         CHECK_NULL_VOID(pipeline);
750         pipeline->AddAfterLayoutTask([weakNavDestiniation = WeakClaim(this),
751             weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] () {
752             auto navDestination = weakNavDestiniation.Upgrade();
753             CHECK_NULL_VOID(navDestination);
754             auto proxy = weakProxy.Upgrade();
755             if (proxy && proxy->GetIsFinished()) {
756                 return;
757             }
758             navDestination->CollectTextNodeAsRenderGroup(false);
759         });
760         pipeline->RequestFrame();
761     }
762 }
763 
CollectTextNodeAsRenderGroup(bool isPopPage)764 void NavDestinationGroupNode::CollectTextNodeAsRenderGroup(bool isPopPage)
765 {
766     ReleaseTextNodeList();
767     std::queue<RefPtr<UINode>> childrenLoopQueue;
768     childrenLoopQueue.push(contentNode_);
769 
770     // only the first 50 text nodes will be marked, avoid too much time for traversal
771     // and off-screen drawing at first few frames
772     int32_t remainTextNodeNeedRenderGroup = MAX_RENDER_GROUP_TEXT_NODE_COUNT;
773     while (!childrenLoopQueue.empty() && remainTextNodeNeedRenderGroup > 0) {
774         auto currentNode = childrenLoopQueue.front();
775         childrenLoopQueue.pop();
776         CHECK_NULL_CONTINUE(currentNode);
777         for (auto& child : currentNode->GetChildren()) {
778             if (remainTextNodeNeedRenderGroup <= 0) {
779                 break;
780             }
781             CHECK_NULL_CONTINUE(child);
782             childrenLoopQueue.push(child);
783             auto frameNode = AceType::DynamicCast<FrameNode>(child);
784             if (!frameNode || (frameNode->GetTag() != V2::TEXT_ETS_TAG)) {
785                 continue;
786             }
787             auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
788             if (!layoutProperty ||
789                 (layoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE)) {
790                 continue;
791             }
792             auto& renderContext = frameNode->GetRenderContext();
793             if (!renderContext || renderContext->GetRenderGroupValue(false)) {
794                 continue;
795             }
796             renderContext->SetMarkNodeGroup(isPopPage ||
797                 (renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT));
798             textNodeList_.emplace_back(WeakPtr<UINode>(child));
799             --remainTextNodeNeedRenderGroup;
800             auto pattern = AceType::DynamicCast<TextPattern>(frameNode->GetPattern());
801             CHECK_NULL_CONTINUE(pattern);
802             pattern->RegisterAfterLayoutCallback([weakRenderContext = WeakPtr<RenderContext>(renderContext)]() {
803                 auto renderContext = weakRenderContext.Upgrade();
804                 if (renderContext && !(renderContext->GetRenderGroupValue(false))) {
805                     renderContext->SetMarkNodeGroup(
806                         renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT);
807                 }
808             });
809         }
810     }
811 }
812 
ReleaseTextNodeList()813 void NavDestinationGroupNode::ReleaseTextNodeList()
814 {
815     for (auto& child : textNodeList_) {
816         auto textNode = AceType::DynamicCast<FrameNode>(child.Upgrade());
817         if (!textNode) {
818             continue;
819         }
820         auto pattern = AceType::DynamicCast<TextPattern>(textNode->GetPattern());
821         if (pattern) {
822             pattern->UnRegisterAfterLayoutCallback();
823         }
824         auto renderContext = textNode->GetRenderContext();
825         if (renderContext) {
826             renderContext->SetMarkNodeGroup(renderContext->GetRenderGroupValue(false));
827         }
828     }
829     textNodeList_.clear();
830 }
831 
CleanContent(bool cleanDirectly,bool allowTransition)832 void NavDestinationGroupNode::CleanContent(bool cleanDirectly, bool allowTransition)
833 {
834     // cacheNode is cached for pip info, and is no need to clean when clean content node
835     if (IsCacheNode()) {
836         return;
837     }
838     auto pattern = GetPattern<NavDestinationPattern>();
839     CHECK_NULL_VOID(pattern);
840     auto shallowBuilder = pattern->GetShallowBuilder();
841     if (shallowBuilder) {
842         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
843     }
844     if (GetContentNode()) {
845         GetContentNode()->Clean(cleanDirectly, allowTransition);
846     }
847 }
848 
IsNodeInvisible(const RefPtr<FrameNode> & node)849 bool NavDestinationGroupNode::IsNodeInvisible(const RefPtr<FrameNode>& node)
850 {
851     auto navigation = DynamicCast<NavigationGroupNode>(node);
852     CHECK_NULL_RETURN(navigation, false);
853     int32_t lastStandardIndex = navigation->GetLastStandardIndex();
854     bool isInvisible = index_ < lastStandardIndex;
855     if (!isHomeDestination_) {
856         return isInvisible;
857     }
858     auto navPattern = navigation->GetPattern<NavigationPattern>();
859     CHECK_NULL_RETURN(navPattern, isInvisible);
860     auto mode = navPattern->GetNavigationMode();
861     if (mode == NavigationMode::STACK) {
862         return isInvisible;
863     }
864     return false;
865 }
866 
ToDumpString()867 std::string NavDestinationGroupNode::ToDumpString()
868 {
869     std::string dumpString;
870     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
871     CHECK_NULL_RETURN(navDestinationPattern, dumpString);
872     std::string navDestinationType;
873     switch (destType_) {
874         case NavDestinationType::DETAIL:
875             navDestinationType = "DETAIL";
876             break;
877         case NavDestinationType::HOME:
878             navDestinationType = "HOME";
879             break;
880         case NavDestinationType::PROXY:
881             navDestinationType = "PROXY";
882             break;
883         default:
884             navDestinationType = "INVALID";
885             break;
886     }
887     dumpString.append("| [");
888     dumpString.append(std::to_string(index_));
889     dumpString.append("]{ ID: ");
890     dumpString.append(std::to_string(navDestinationPattern->GetNavDestinationId()));
891     dumpString.append(", Name: \"");
892     dumpString.append(navDestinationPattern->GetName());
893     dumpString.append("\", Mode: \"");
894     dumpString.append(mode_ == NavDestinationMode::STANDARD ? "STANDARD" : "DIALOG");
895     dumpString.append("\", IsOnShow: \"");
896     dumpString.append(navDestinationPattern->GetIsOnShow() ? "TRUE" : "FALSE");
897     dumpString.append("\", navDestinationType: \"");
898     dumpString.append(navDestinationType);
899     dumpString.append("\", Visible? \"");
900     dumpString.append(IsVisible() ? "Yes" : "No");
901     int32_t count = 0;
902     int32_t depth = 0;
903     GetPageNodeCountAndDepth(&count, &depth);
904     dumpString.append("\", Count: " + std::to_string(count));
905     dumpString.append(", Depth: " + std::to_string(depth) + " }");
906     return dumpString;
907 }
908 
DoTransition(NavigationOperation operation,bool isEnter)909 int32_t NavDestinationGroupNode::DoTransition(NavigationOperation operation, bool isEnter)
910 {
911     if (destType_ == NavDestinationType::HOME) {
912         return INVALID_ANIMATION_ID;
913     }
914     if (navDestinationTransitionDelegate_) {
915         return DoCustomTransition(operation, isEnter);
916     }
917     return DoSystemTransition(operation, isEnter);
918 }
919 
DoSystemTransition(NavigationOperation operation,bool isEnter)920 int32_t NavDestinationGroupNode::DoSystemTransition(NavigationOperation operation, bool isEnter)
921 {
922     auto noneSystemTransition = NavigationSystemTransitionType::NONE;
923     if ((systemTransitionType_ & NavigationSystemTransitionType::FADE) != noneSystemTransition) {
924         return DoSystemFadeTransition(isEnter);
925     }
926     if ((systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT) != noneSystemTransition ||
927         (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_BOTTOM) != noneSystemTransition) {
928         return DoSystemSlideTransition(operation, isEnter);
929     }
930     if ((systemTransitionType_ & NavigationSystemTransitionType::EXPLODE) != noneSystemTransition) {
931         return isEnter ? DoSystemEnterExplodeTransition(operation) : DoSystemExitExplodeTransition(operation);
932     }
933     return INVALID_ANIMATION_ID;
934 }
935 
DoSystemFadeTransition(bool isEnter)936 int32_t NavDestinationGroupNode::DoSystemFadeTransition(bool isEnter)
937 {
938     auto renderContext = GetRenderContext();
939     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
940     auto eventHub = GetOrCreateEventHub<EventHub>();
941     if (!inCurrentStack_ && eventHub) {
942         eventHub->SetEnabledInternal(false);
943     }
944     animationId_ = MakeUniqueAnimationId();
945     SetIsOnAnimation(true);
946     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
947         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DURATION : SYSTEM_EXIT_FADE_TRANSITION_DURATION,
948         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DELAY : SYSTEM_EXIT_FADE_TRANSITION_DELAY);
949     OnStartOneTransitionAnimation();
950     renderContext->OpacityAnimation(option, isEnter ? 0.0f : 1.0f, isEnter ? 1.0f : 0.0f);
951     return animationId_;
952 }
953 
DoSystemSlideTransition(NavigationOperation operation,bool isEnter)954 int32_t NavDestinationGroupNode::DoSystemSlideTransition(NavigationOperation operation, bool isEnter)
955 {
956     auto eventHub = GetOrCreateEventHub<EventHub>();
957     if (!inCurrentStack_ && eventHub) {
958         eventHub->SetEnabledInternal(false);
959     }
960     animationId_ = MakeUniqueAnimationId();
961     SetIsOnAnimation(true);
962     if ((operation == NavigationOperation::POP) ^ isEnter) {
963         // translate animation
964         bool isRight = (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT)
965             != NavigationSystemTransitionType::NONE;
966         std::function<void()> translateEvent = [weak = WeakClaim(this), isEnter, isRight, operation]() {
967             auto navDestination = weak.Upgrade();
968             CHECK_NULL_VOID(navDestination);
969             auto renderContext = navDestination->GetRenderContext();
970             CHECK_NULL_VOID(renderContext);
971             auto paintRect = renderContext->GetPaintRectWithoutTransform().GetSize();
972             auto translate = navDestination->CalcTranslateForSlideTransition(paintRect, isRight, isEnter, true);
973             renderContext->UpdateTranslateInXY(translate);
974         };
975         RefPtr<Curve> curve = isRight ? MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f)
976             : MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
977         auto option = BuildAnimationOption(curve, BuildTransitionFinishCallback());
978         auto renderContext = GetRenderContext();
979         auto paintRect = renderContext->GetPaintRectWithoutTransform().GetSize();
980         auto translate = CalcTranslateForSlideTransition(paintRect, isRight, isEnter, false);
981         renderContext->UpdateTranslateInXY(translate);
982         OnStartOneTransitionAnimation();
983         AnimationUtils::Animate(
984             option, translateEvent, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
985     } else {
986         // mask animation
987         auto option = BuildAnimationOption(
988             Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_SLIDE_TRANSITION_MASK_DURATION);
989         auto beginColor = isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
990         auto endColor = !isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
991         OnStartOneTransitionAnimation();
992         DoMaskAnimation(option, beginColor, endColor);
993     }
994     return animationId_;
995 }
996 
997 
DoSystemEnterExplodeTransition(NavigationOperation operation)998 int32_t NavDestinationGroupNode::DoSystemEnterExplodeTransition(NavigationOperation operation)
999 {
1000     auto renderContext = GetRenderContext();
1001     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
1002     auto eventHub = GetOrCreateEventHub<EventHub>();
1003     if (!inCurrentStack_ && eventHub) {
1004         eventHub->SetEnabledInternal(false);
1005     }
1006     animationId_ = MakeUniqueAnimationId();
1007     SetIsOnAnimation(true);
1008     if (operation == NavigationOperation::POP) {
1009         OnStartOneTransitionAnimation();
1010         // mask animation
1011         DoMaskAnimation(
1012             BuildAnimationOption(Curves::FRICTION, BuildEmptyFinishCallback(), SYSTEM_EXPLODE_TRANSITION_MASK_DURATION),
1013             SLIDE_ANIMATION_MASK_COLOR, Color::TRANSPARENT);
1014         // opacity animation
1015         auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
1016             SYSTEM_ENTER_POP_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_POP_EXPLODE_OPACITY_DELAY);
1017         OnStartOneTransitionAnimation();
1018         renderContext->OpacityAnimation(option, 0.0f, 1.0f);
1019         return animationId_;
1020     }
1021     // opacity animation
1022     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
1023         SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DELAY);
1024     OnStartOneTransitionAnimation();
1025     renderContext->OpacityAnimation(option, 0.0f, 1.0f);
1026     // scale animation for enter-push
1027     auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
1028     OnStartOneTransitionAnimation();
1029     renderContext->ScaleAnimation(
1030         BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback()), 0.75f, 1.0f);
1031     return animationId_;
1032 }
1033 
DoSystemExitExplodeTransition(NavigationOperation operation)1034 int32_t NavDestinationGroupNode::DoSystemExitExplodeTransition(NavigationOperation operation)
1035 {
1036     auto renderContext = GetRenderContext();
1037     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
1038     auto eventHub = GetOrCreateEventHub<EventHub>();
1039     if (!inCurrentStack_ && eventHub) {
1040         eventHub->SetEnabledInternal(false);
1041     }
1042     animationId_ = MakeUniqueAnimationId();
1043     SetIsOnAnimation(true);
1044     if (operation == NavigationOperation::POP) {
1045         OnStartOneTransitionAnimation();
1046         // opacity animation
1047         renderContext->OpacityAnimation(BuildAnimationOption(
1048             Curves::SHARP, BuildEmptyFinishCallback(), SYSTEM_EXIT_POP_EXPLODE_OPACITY_DURATION), 1.0f, 0.0f);
1049         // scale animation
1050         auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
1051         auto option = BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback());
1052         OnStartOneTransitionAnimation();
1053         renderContext->ScaleAnimation(option, 1.0f, 0.8f);
1054         return animationId_;
1055     }
1056     OnStartOneTransitionAnimation();
1057     // opacity animation
1058     renderContext->OpacityAnimation(
1059         BuildAnimationOption(Curves::SHARP, BuildEmptyFinishCallback(), SYSTEM_EXIT_PUSH_EXPLODE_OPACITY_DELAY),
1060         1.0f, 0.0f);
1061     // mask animation
1062     auto maskOption = BuildAnimationOption(
1063         Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_EXPLODE_TRANSITION_MASK_DURATION);
1064     OnStartOneTransitionAnimation();
1065     DoMaskAnimation(maskOption, Color::TRANSPARENT, SLIDE_ANIMATION_MASK_COLOR);
1066     return animationId_;
1067 }
1068 
DoMaskAnimation(const AnimationOption & option,Color begin,Color end)1069 void NavDestinationGroupNode::DoMaskAnimation(const AnimationOption& option, Color begin, Color end)
1070 {
1071     auto renderContext = GetRenderContext();
1072     CHECK_NULL_VOID(renderContext);
1073     std::function<void()> maskEvent = [weak = WeakClaim(this), end]() {
1074         auto navDestination = weak.Upgrade();
1075         CHECK_NULL_VOID(navDestination);
1076         auto renderContext = navDestination->GetRenderContext();
1077         CHECK_NULL_VOID(renderContext);
1078         renderContext->SetActualForegroundColor(end);
1079     };
1080 
1081     // initial property
1082     renderContext->SetActualForegroundColor(begin);
1083     AnimationUtils::Animate(
1084         option, maskEvent, option.GetOnFinishEvent(), nullptr /* repeatCallback */, GetContextRefPtr());
1085 }
1086 
DoCustomTransition(NavigationOperation operation,bool isEnter)1087 int32_t NavDestinationGroupNode::DoCustomTransition(NavigationOperation operation, bool isEnter)
1088 {
1089     auto delegate = navDestinationTransitionDelegate_;
1090     if (!delegate) {
1091         return INVALID_ANIMATION_ID;
1092     }
1093     auto eventHub = GetOrCreateEventHub<EventHub>();
1094     if (!inCurrentStack_ && eventHub) {
1095         eventHub->SetEnabledInternal(false);
1096     }
1097     auto allTransitions = delegate(operation, isEnter);
1098     if (!allTransitions.has_value()) {
1099         return INVALID_ANIMATION_ID;
1100     }
1101     int32_t longestAnimationDuration = INT32_MIN;
1102     for (auto transition: allTransitions.value()) {
1103         if (transition.duration + transition.delay > longestAnimationDuration) {
1104             longestAnimationDuration = transition.duration + transition.delay;
1105         }
1106     }
1107     if (longestAnimationDuration != INT32_MIN) {
1108         SetIsOnAnimation(true);
1109     } else {
1110         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navDestination custom transition array is empty!");
1111     }
1112     auto pipeline = GetContext();
1113     CHECK_NULL_RETURN(pipeline, INVALID_ANIMATION_ID);
1114     pipeline->FlushBuild();
1115     pipeline->FlushUITasks();
1116     animationId_ = MakeUniqueAnimationId();
1117     bool hasRest = false;
1118     for (auto transition: allTransitions.value()) {
1119         StartCustomTransitionAnimation(transition, isEnter, hasRest, longestAnimationDuration);
1120     }
1121     return animationId_;
1122 }
1123 
StartCustomTransitionAnimation(NavDestinationTransition & transition,bool isEnter,bool & hasResetProperties,int32_t longestAnimationDuration)1124 void NavDestinationGroupNode::StartCustomTransitionAnimation(NavDestinationTransition& transition,
1125     bool isEnter, bool& hasResetProperties, int32_t longestAnimationDuration)
1126 {
1127     AnimationOption option;
1128     option.SetDuration(transition.duration);
1129     option.SetCurve(transition.curve);
1130     option.SetDelay(transition.delay);
1131 
1132     std::function<void()> event =
1133         [transitionEvent = std::move(transition.event), weak = WeakClaim(this), isEnter, &hasResetProperties]() {
1134             // do necessary system-side tasks
1135             auto navDestination = weak.Upgrade();
1136             CHECK_NULL_VOID(navDestination);
1137             if (!hasResetProperties && isEnter) {
1138                 auto pattern = navDestination->GetPattern<NavDestinationPattern>();
1139                 CHECK_NULL_VOID(pattern);
1140                 auto navigation = AceType::DynamicCast<NavigationGroupNode>(pattern->GetNavigationNode());
1141                 if (navigation) {
1142                     /*
1143                     *  Reset the system animation properties in custom transition
1144                     *  animation closure to prevent animation mutation.
1145                     */
1146                     navigation->ResetSystemAnimationProperties(navDestination);
1147                 }
1148                 hasResetProperties = true;
1149             }
1150             // do user-set task
1151             transitionEvent();
1152             auto pipeline = navDestination->GetContext();
1153             CHECK_NULL_VOID(pipeline);
1154             pipeline->FlushBuild();
1155             pipeline->FlushUITasks();
1156         };
1157     std::function<void()> finish;
1158     // only do remove or set visibility in longest custom transition animation's finish callback.
1159     if (transition.duration + transition.delay == longestAnimationDuration) {
1160         finish = BuildTransitionFinishCallback(false, std::move(transition.onTransitionEnd));
1161     } else {
1162         finish = [onTransitionEnd = std::move(transition.onTransitionEnd), weak = WeakClaim(this)]() {
1163             auto node = weak.Upgrade();
1164             if (onTransitionEnd) {
1165                 onTransitionEnd();
1166             }
1167             CHECK_NULL_VOID(node);
1168             node->OnFinishOneTransitionAnimation();
1169         };
1170     }
1171     OnStartOneTransitionAnimation();
1172     AnimationUtils::Animate(option, event, finish, nullptr /* repeatCallback */, GetContextRefPtr());
1173     auto pattern = GetPattern<NavDestinationPattern>();
1174     CHECK_NULL_VOID(pattern);
1175     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
1176         "%{public}s trigger custom transition, duration: %{public}d, delay: %{public}d, curve: %{public}s",
1177         pattern->GetName().c_str(), transition.duration, transition.delay, transition.curve->ToString().c_str());
1178 }
1179 
MakeUniqueAnimationId()1180 int32_t NavDestinationGroupNode::MakeUniqueAnimationId()
1181 {
1182     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
1183     CHECK_NULL_RETURN(navDestinationPattern, INVALID_ANIMATION_ID);
1184     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
1185     CHECK_NULL_RETURN(navigationNode, INVALID_ANIMATION_ID);
1186     return navigationNode->MakeUniqueAnimationId();
1187 }
1188 
BuildTransitionFinishCallback(bool isSystemTransition,std::function<void ()> && extraOption)1189 std::function<void()> NavDestinationGroupNode::BuildTransitionFinishCallback(
1190     bool isSystemTransition, std::function<void()>&& extraOption)
1191 {
1192     std::function<void()> finish = [extraOption = std::move(extraOption), weak = WeakClaim(this),
1193         animationId = animationId_, isSystemTransition]() {
1194             auto navDestination = weak.Upgrade();
1195             CHECK_NULL_VOID(navDestination);
1196             auto destinationPattern = navDestination->GetPattern<NavDestinationPattern>();
1197             CHECK_NULL_VOID(destinationPattern);
1198             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s transition finish", destinationPattern->GetName().c_str());
1199             // do extraOption first
1200             if (extraOption) {
1201                 extraOption();
1202             }
1203             // do necessary system-side tasks
1204             if (animationId != navDestination->GetAnimationId()) {
1205                 return;
1206             }
1207             if (isSystemTransition) {
1208                 navDestination->ResetCustomTransitionAnimationProperties();
1209             }
1210             if (navDestination->IsHomeDestination()) {
1211                 auto navNode = AceType::DynamicCast<NavigationGroupNode>(navDestination->GetNavigationNode());
1212                 CHECK_NULL_VOID(navNode);
1213                 auto navPattern = navNode->GetPattern<NavigationPattern>();
1214                 CHECK_NULL_VOID(navPattern);
1215                 auto mode = navPattern->GetNavigationMode();
1216                 if (mode == NavigationMode::STACK && navDestination->HasStandardBefore()) {
1217                     navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1218                     navDestination->SetJSViewActive(false);
1219                 }
1220                 navDestination->SetIsOnAnimation(false);
1221                 return;
1222             }
1223             // only handle current node in latest finish callback.
1224             if (!navDestination->GetInCurrentStack()) {
1225                 // can't be reused means it is not in navigation stack anymore, so remove it.
1226                 navDestination->CleanContent(false, true);
1227                 auto parent = navDestination->GetParent();
1228                 CHECK_NULL_VOID(parent);
1229                 parent->RemoveChild(navDestination);
1230                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1231             } else if (navDestination->HasStandardBefore()) {
1232                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
1233                 navDestination->SetJSViewActive(false);
1234             }
1235             navDestination->SetIsOnAnimation(false);
1236         };
1237     auto finisWrapper = [onFinish = std::move(finish), weak = WeakClaim(this)]() {
1238         auto node = weak.Upgrade();
1239         if (onFinish) {
1240             onFinish();
1241         }
1242         CHECK_NULL_VOID(node);
1243         node->OnFinishOneTransitionAnimation();
1244     };
1245     return finisWrapper;
1246 }
1247 
BuildEmptyFinishCallback()1248 std::function<void()> NavDestinationGroupNode::BuildEmptyFinishCallback()
1249 {
1250     auto finish = [weak = WeakClaim(this)]() {
1251         auto node = weak.Upgrade();
1252         CHECK_NULL_VOID(node);
1253         node->OnFinishOneTransitionAnimation();
1254     };
1255     return finish;
1256 }
1257 
HasStandardBefore() const1258 bool NavDestinationGroupNode::HasStandardBefore() const
1259 {
1260     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
1261     CHECK_NULL_RETURN(navDestinationPattern, false);
1262     auto navigationNode =
1263         AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
1264     CHECK_NULL_RETURN(navigationNode, false);
1265     return index_ < navigationNode->GetLastStandardIndex();
1266 }
1267 
ResetCustomTransitionAnimationProperties()1268 void NavDestinationGroupNode::ResetCustomTransitionAnimationProperties()
1269 {
1270     auto renderContext = GetRenderContext();
1271     CHECK_NULL_VOID(renderContext);
1272     renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
1273     renderContext->SetOpacity(userSetOpacity_);
1274     renderContext->SetActualForegroundColor(Color::TRANSPARENT);
1275 }
1276 
GetNavigationNode()1277 RefPtr<UINode> NavDestinationGroupNode::GetNavigationNode()
1278 {
1279     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
1280     CHECK_NULL_RETURN(navDestinationPattern, nullptr);
1281     return navDestinationPattern->GetNavigationNode();
1282 }
1283 
GetNavDestinationMode() const1284 NavDestinationMode NavDestinationGroupNode::GetNavDestinationMode() const
1285 {
1286     if (destType_ == NavDestinationType::PROXY) {
1287         auto primaryNode = primaryNode_.Upgrade();
1288         CHECK_NULL_RETURN(primaryNode, mode_);
1289         return primaryNode->GetNavDestinationMode();
1290     }
1291     return mode_;
1292 }
1293 
GetOrCreateProxyNode()1294 RefPtr<NavDestinationGroupNode> NavDestinationGroupNode::GetOrCreateProxyNode()
1295 {
1296     if (proxyNode_) {
1297         return proxyNode_;
1298     }
1299 
1300     auto proxyNode = ForceSplitUtils::CreateNavDestinationProxyNode();
1301     CHECK_NULL_RETURN(proxyNode, nullptr);
1302     proxyNode->SetPrimaryNode(WeakClaim(this));
1303     auto proxyPattern = proxyNode->GetPattern<NavDestinationPattern>();
1304     CHECK_NULL_RETURN(proxyPattern, nullptr);
1305     proxyPattern->SetIndex(index_);
1306     proxyNode_ = proxyNode;
1307     return proxyNode_;
1308 }
1309 
SetIndex(int32_t index,bool updatePrimary)1310 void NavDestinationGroupNode::SetIndex(int32_t index, bool updatePrimary)
1311 {
1312     index_ = index;
1313     if (destType_ == NavDestinationType::PROXY && updatePrimary) {
1314         auto primaryNode = primaryNode_.Upgrade();
1315         CHECK_NULL_VOID(primaryNode);
1316         primaryNode->SetIndex(index, false);
1317     } else if (proxyNode_) {
1318         proxyNode_->SetIndex(index, false);
1319     }
1320 }
1321 
SetCanReused(bool canReused)1322 void NavDestinationGroupNode::SetCanReused(bool canReused)
1323 {
1324     if (destType_ == NavDestinationType::PROXY) {
1325         auto primaryNode = primaryNode_.Upgrade();
1326         if (primaryNode) {
1327             primaryNode->SetCanReused(canReused);
1328         }
1329     }
1330     canReused_ = canReused;
1331 }
1332 
GetCanReused() const1333 bool NavDestinationGroupNode::GetCanReused() const
1334 {
1335     if (destType_ == NavDestinationType::PROXY) {
1336         auto primaryNode = primaryNode_.Upgrade();
1337         if (primaryNode) {
1338             return primaryNode->GetCanReused();
1339         }
1340     }
1341     return canReused_;
1342 }
1343 } // namespace OHOS::Ace::NG
1344