• 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/components_ng/pattern/navigation/navigation_pattern.h"
19 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
20 #include "core/components_ng/pattern/navigation/navigation_transition_proxy.h"
21 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
22 #include "core/components_ng/pattern/text/text_pattern.h"
23 #include "core/components_v2/inspector/inspector_constants.h"
24 
25 namespace OHOS::Ace::NG {
26 constexpr double HALF = 0.5;
27 constexpr float CONTENT_OFFSET_PERCENT = 0.2f;
28 constexpr float TITLE_OFFSET_PERCENT = 0.02f;
29 constexpr float REMOVE_CLIP_SIZE = 10000.0f;
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         return true;
111     }
112     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
113 }
114 
TransitionContentInValid()115 bool NavDestinationGroupNode::TransitionContentInValid()
116 {
117     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) == NavigationSystemTransitionType::NONE
118         && mode_ == NavDestinationMode::STANDARD;
119 }
120 
IsNeedTitleTransition()121 bool NavDestinationGroupNode::IsNeedTitleTransition()
122 {
123     if (systemTransitionType_ == NavigationSystemTransitionType::DEFAULT) {
124         return true;
125     }
126     if (mode_ == NavDestinationMode::STANDARD) {
127         return (systemTransitionType_ & NavigationSystemTransitionType::TITLE) != NavigationSystemTransitionType::NONE;
128     }
129     return (systemTransitionType_ & NavigationSystemTransitionType::CONTENT) != NavigationSystemTransitionType::NONE;
130 }
131 
AddChildToGroup(const RefPtr<UINode> & child,int32_t slot)132 void NavDestinationGroupNode::AddChildToGroup(const RefPtr<UINode>& child, int32_t slot)
133 {
134     auto pattern = AceType::DynamicCast<Pattern>(GetPattern());
135     CHECK_NULL_VOID(pattern);
136     auto contentNode = GetContentNode();
137     if (!contentNode) {
138         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
139         ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId);
140         contentNode = FrameNode::GetOrCreateFrameNode(V2::NAVDESTINATION_CONTENT_ETS_TAG, nodeId,
141             []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
142         SetContentNode(contentNode);
143         AddChild(contentNode);
144 
145         if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
146             auto navdestinationContentNode = AceType::DynamicCast<FrameNode>(contentNode);
147             SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
148                 .edges = SAFE_AREA_EDGE_ALL };
149             navdestinationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
150         }
151     }
152     contentNode->AddChild(child, slot);
153 }
154 
DeleteChildFromGroup(int32_t slot)155 void NavDestinationGroupNode::DeleteChildFromGroup(int32_t slot)
156 {
157     auto navDestination = GetContentNode();
158     CHECK_NULL_VOID(navDestination);
159     navDestination->RemoveChildAtIndex(slot);
160 }
161 
OnAttachToMainTree(bool recursive)162 void NavDestinationGroupNode::OnAttachToMainTree(bool recursive)
163 {
164     if (!UseOffscreenProcess()) {
165         ProcessShallowBuilder();
166     }
167     FrameNode::OnAttachToMainTree(recursive);
168     SetFreeze(false, true);
169 }
170 
OnOffscreenProcess(bool recursive)171 void NavDestinationGroupNode::OnOffscreenProcess(bool recursive)
172 {
173     ProcessShallowBuilder();
174     FrameNode::OnOffscreenProcess(recursive);
175 }
176 
ProcessShallowBuilder()177 void NavDestinationGroupNode::ProcessShallowBuilder()
178 {
179     if (isCacheNode_) {
180         return;
181     }
182 
183     TAG_LOGD(AceLogTag::ACE_NAVIGATION, "render navDestination content");
184     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
185     CHECK_NULL_VOID(navDestinationPattern);
186     auto shallowBuilder = navDestinationPattern->GetShallowBuilder();
187     if (shallowBuilder && !shallowBuilder->IsExecuteDeepRenderDone()) {
188         auto eventHub = GetEventHub<NavDestinationEventHub>();
189         if (eventHub) {
190             auto ctx = navDestinationPattern->GetNavDestinationContext();
191             eventHub->FireOnReady(ctx);
192         }
193         shallowBuilder->ExecuteDeepRender();
194         GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
195         AceType::DynamicCast<FrameNode>(contentNode_)
196             ->GetLayoutProperty()
197             ->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
198     }
199 }
200 
GetNavDestinationCustomNode()201 RefPtr<CustomNodeBase> NavDestinationGroupNode::GetNavDestinationCustomNode()
202 {
203     return customNode_.Upgrade();
204 }
205 
GetNavigationNodeId() const206 int32_t NavDestinationGroupNode::GetNavigationNodeId() const
207 {
208     auto pattern = AceType::DynamicCast<NavDestinationPattern>(GetPattern());
209     CHECK_NULL_RETURN(pattern, DEFAULT_NODE_SLOT);
210     auto navigationNode = pattern->GetNavigationNode();
211     CHECK_NULL_RETURN(navigationNode, DEFAULT_NODE_SLOT);
212     return navigationNode->GetId();
213 }
214 
SetNavDestinationMode(NavDestinationMode mode)215 void NavDestinationGroupNode::SetNavDestinationMode(NavDestinationMode mode)
216 {
217     mode_ = mode;
218     auto pattern = GetPattern<NavDestinationPattern>();
219     CHECK_NULL_VOID(pattern);
220     auto context = pattern->GetNavDestinationContext();
221     CHECK_NULL_VOID(context);
222     context->SetMode(mode);
223 }
224 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const225 void NavDestinationGroupNode::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
226 {
227     FrameNode::ToJsonValue(json, filter);
228     /* no fixed attr below, just return */
229     if (filter.IsFastFilter()) {
230         return;
231     }
232     auto titleBarNode = DynamicCast<TitleBarNode>(titleBarNode_);
233     if (titleBarNode) {
234         std::string title = NavigationTitleUtil::GetTitleString(titleBarNode, GetPrevTitleIsCustomValue(false));
235         std::string subtitle = NavigationTitleUtil::GetSubtitleString(titleBarNode);
236         json->PutExtAttr("title", title.c_str(), filter);
237         json->PutExtAttr("subtitle", subtitle.c_str(), filter);
238     }
239     json->PutExtAttr("mode", mode_ == NavDestinationMode::DIALOG
240         ? "NavDestinationMode::DIALOG"
241         : "NavDestinationMode::STANDARD", filter);
242     json->PutExtAttr("systemTransition", TransitionTypeToString(systemTransitionType_), filter);
243 }
244 
InitSystemTransitionPush(bool transitionIn)245 void NavDestinationGroupNode::InitSystemTransitionPush(bool transitionIn)
246 {
247     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
248     float isRTL = GetLanguageDirection();
249     bool needContentAnimation = IsNeedContentTransition();
250     bool needTitleAnimation = IsNeedTitleTransition();
251     if (transitionIn) {
252         SetIsOnAnimation(true);
253         SetTransitionType(PageTransitionType::ENTER_PUSH);
254         auto frameSize = GetGeometryNode()->GetFrameSize();
255         if (needContentAnimation) {
256             if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
257                 GetRenderContext()->ClipWithRRect(
258                     RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
259             } else {
260                 GetRenderContext()->ClipWithRRect(
261                     RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
262                     RadiusF(EdgeF(0.0f, 0.0f)));
263             }
264             GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
265         }
266         if (titleBarNode && needTitleAnimation) {
267             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
268         }
269         return;
270     }
271     SetTransitionType(PageTransitionType::EXIT_PUSH);
272     SetIsOnAnimation(true);
273     GetRenderContext()->RemoveClipWithRRect();
274     if (needContentAnimation) {
275         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
276     }
277     if (NeedRemoveInPush()) {
278         GetEventHub<EventHub>()->SetEnabledInternal(false);
279     }
280     if (titleBarNode && needTitleAnimation) {
281         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
282     }
283 }
284 
StartSystemTransitionPush(bool transitionIn)285 void NavDestinationGroupNode::StartSystemTransitionPush(bool transitionIn)
286 {
287     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
288     auto frameSize = GetGeometryNode()->GetFrameSize();
289     float isRTL = GetLanguageDirection();
290     bool needContentAnimation = IsNeedContentTransition();
291     bool needTitleAnimation = IsNeedTitleTransition();
292     if (transitionIn) {
293         if (needContentAnimation) {
294             GetRenderContext()->ClipWithRRect(
295                 RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
296             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
297         }
298         if (titleBarNode && needTitleAnimation) {
299             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
300         }
301         return;
302     }
303     if (needContentAnimation) {
304         GetRenderContext()->UpdateTranslateInXY(
305             { -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
306     }
307     if (titleBarNode && needTitleAnimation) {
308         titleBarNode->GetRenderContext()->UpdateTranslateInXY(
309             { frameSize.Width() * TITLE_OFFSET_PERCENT  * isRTL, 0.0f });
310     }
311 }
312 
SystemTransitionPushCallback(bool transitionIn,const int32_t animationId)313 void NavDestinationGroupNode::SystemTransitionPushCallback(bool transitionIn, const int32_t animationId)
314 {
315     if (animationId != animationId_) {
316         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "push animation invalid,curId: %{public}d, targetId: %{public}d",
317             animationId_, animationId);
318         return;
319     }
320     SetIsOnAnimation(false);
321     if (transitionIn) {
322         if (GetTransitionType() != PageTransitionType::ENTER_PUSH) {
323             TAG_LOGW(AceLogTag::ACE_NAVIGATION, "curNode has another transition");
324             return;
325         }
326         GetRenderContext()->RemoveClipWithRRect();
327         return;
328     }
329     if (IsNeedContentTransition()) {
330         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
331     }
332     GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
333     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
334     CHECK_NULL_VOID(navDestinationPattern);
335     auto navigation = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
336     CHECK_NULL_VOID(navigation);
337     bool isInvisible = IsNodeInvisible(navigation);
338     if (GetTransitionType() == PageTransitionType::EXIT_PUSH && isInvisible) {
339         GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
340         SetJSViewActive(false);
341     }
342     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
343     if (titleBarNode && IsNeedTitleTransition()) {
344         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
345     }
346 }
347 
InitSystemTransitionPop(bool isTransitionIn)348 void NavDestinationGroupNode::InitSystemTransitionPop(bool isTransitionIn)
349 {
350     auto frameSize = GetGeometryNode()->GetFrameSize();
351     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
352     float isRTL = GetLanguageDirection();
353     bool needContentAnimation = IsNeedContentTransition();
354     bool needTitleAnimation = IsNeedTitleTransition();
355     if (isTransitionIn) {
356         SetTransitionType(PageTransitionType::ENTER_POP);
357         GetRenderContext()->RemoveClipWithRRect();
358         if (needContentAnimation) {
359             GetRenderContext()->UpdateTranslateInXY({ -frameSize.Width() * CONTENT_OFFSET_PERCENT * isRTL, 0.0f });
360         }
361         if (titleBarNode && needTitleAnimation) {
362             titleBarNode->GetRenderContext()->UpdateTranslateInXY(
363                 { frameSize.Width() * TITLE_OFFSET_PERCENT * isRTL, 0.0f });
364         }
365         return;
366     }
367     SetIsOnAnimation(true);
368     SetTransitionType(PageTransitionType::EXIT_POP);
369     GetEventHub<EventHub>()->SetEnabledInternal(false);
370     if (needContentAnimation) {
371         GetRenderContext()->ClipWithRRect(RectF(0.0f, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
372             RadiusF(EdgeF(0.0f, 0.0f)));
373         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
374     }
375     if (titleBarNode && needTitleAnimation) {
376         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
377     }
378 }
379 
StartSystemTransitionPop(bool transitionIn)380 void NavDestinationGroupNode::StartSystemTransitionPop(bool transitionIn)
381 {
382     auto titleBarNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
383     bool needContentAnimation = IsNeedContentTransition();
384     bool needTitleAnimation = IsNeedTitleTransition();
385     if (transitionIn) {
386         if (needContentAnimation) {
387             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
388         }
389         if (titleBarNode && needTitleAnimation) {
390             titleBarNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
391         }
392         return;
393     }
394     auto frameSize = GetGeometryNode()->GetFrameSize();
395     float isRTL = GetLanguageDirection();
396     if (needContentAnimation) {
397         if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
398             GetRenderContext()->ClipWithRRect(
399                 RectF(0.0f, 0.0f, frameSize.Width() * HALF, REMOVE_CLIP_SIZE), RadiusF(EdgeF(0.0f, 0.0f)));
400         } else {
401             GetRenderContext()->ClipWithRRect(
402                 RectF(frameSize.Width() * HALF, 0.0f, frameSize.Width(), REMOVE_CLIP_SIZE),
403                 RadiusF(EdgeF(0.0f, 0.0f)));
404         }
405         GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
406     }
407     if (titleBarNode && needTitleAnimation) {
408         titleBarNode->GetRenderContext()->UpdateTranslateInXY({ frameSize.Width() * HALF * isRTL, 0.0f });
409     }
410 }
411 
CheckTransitionPop(const int32_t animationId)412 bool NavDestinationGroupNode::CheckTransitionPop(const int32_t animationId)
413 {
414     if (IsCacheNode()) {
415         return false;
416     }
417     if (animationId_ != animationId) {
418         return false;
419     }
420     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
421         return false;
422     }
423     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
424     CHECK_NULL_RETURN(preNavDesPattern, false);
425     return true;
426 }
427 
SystemTransitionPopCallback(const int32_t animationId,bool isNeedCleanContent)428 bool NavDestinationGroupNode::SystemTransitionPopCallback(const int32_t animationId, bool isNeedCleanContent)
429 {
430     if (animationId_ != animationId) {
431         TAG_LOGW(AceLogTag::ACE_NAVIGATION,
432             "animation id is invalid, curId: %{public}d, targetId: %{public}d",
433             animationId_, animationId);
434         return false;
435     }
436     SetIsOnAnimation(false);
437     if (GetTransitionType() != PageTransitionType::EXIT_POP) {
438         // has another transition, just return
439         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "preNavDesNode has another transition");
440         return false;
441     }
442     auto preNavDesPattern = GetPattern<NavDestinationPattern>();
443     CHECK_NULL_RETURN(preNavDesPattern, false);
444 
445     // NavRouter will restore the preNavDesNode and needs to set the initial state after the animation ends.
446     CleanContent();
447     GetEventHub<EventHub>()->SetEnabledInternal(true);
448     GetRenderContext()->RemoveClipWithRRect();
449     if (IsNeedContentTransition()) {
450         GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
451     }
452     auto preTitleNode = AceType::DynamicCast<FrameNode>(GetTitleBarNode());
453     if (preTitleNode && IsNeedTitleTransition()) {
454         preTitleNode->GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
455         preTitleNode->GetRenderContext()->SetOpacity(1.0);
456         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(preTitleNode);
457         CHECK_NULL_RETURN(titleBarNode, true);
458         auto preBackIcon = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
459         if (preBackIcon)  {
460             preBackIcon->GetRenderContext()->SetOpacity(1.0);
461         }
462     }
463     return true;
464 }
465 
InitDialogTransition(bool isZeroY)466 void NavDestinationGroupNode::InitDialogTransition(bool isZeroY)
467 {
468     if (systemTransitionType_ == NavigationSystemTransitionType::NONE
469         || systemTransitionType_ == NavigationSystemTransitionType::TITLE) {
470         return;
471     }
472     auto contentNode = AceType::DynamicCast<FrameNode>(GetContentNode());
473     CHECK_NULL_VOID(contentNode);
474     auto context = contentNode->GetRenderContext();
475     CHECK_NULL_VOID(context);
476     if (isZeroY) {
477         context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
478         return;
479     }
480     context->UpdateTransformTranslate({ 0.0f,
481         contentNode->GetGeometryNode()->GetFrameSize().Height(), 0.0f });
482 }
483 
TitleOpacityAnimation(bool isTransitionIn)484 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::TitleOpacityAnimation(bool isTransitionIn)
485 {
486     if (!IsNeedTitleTransition()) {
487         return nullptr;
488     }
489     CHECK_NULL_RETURN(GetTitleBarNode(), nullptr);
490     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
491     CHECK_NULL_RETURN(titleNode, nullptr);
492     auto titleRenderContext = titleNode->GetRenderContext();
493     CHECK_NULL_RETURN(titleRenderContext, nullptr);
494     AnimationOption opacityOption;
495     opacityOption.SetCurve(Curves::SHARP);
496     opacityOption.SetDuration(OPACITY_TITLE_DURATION);
497     if (isTransitionIn) {
498         opacityOption.SetDelay(OPACITY_TITLE_IN_DELAY);
499         titleRenderContext->SetOpacity(0.0f);
500         return AnimationUtils::StartAnimation(opacityOption,
501             [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
502             auto renderContext = weakRender.Upgrade();
503             CHECK_NULL_VOID(renderContext);
504             renderContext->SetOpacity(1.0f);
505         });
506     }
507     // recover after transition animation.
508     opacityOption.SetDelay(OPACITY_TITLE_OUT_DELAY);
509     titleRenderContext->SetOpacity(1.0f);
510     return AnimationUtils::StartAnimation(opacityOption,
511         [weakRender = WeakPtr<RenderContext>(titleRenderContext)]() {
512         auto renderContext = weakRender.Upgrade();
513         CHECK_NULL_VOID(renderContext);
514         renderContext->SetOpacity(0.0f);
515     });
516 }
517 
BackButtonAnimation(bool isTransitionIn)518 std::shared_ptr<AnimationUtils::Animation> NavDestinationGroupNode::BackButtonAnimation(bool isTransitionIn)
519 {
520     if (!IsNeedTitleTransition()) {
521         return nullptr;
522     }
523     auto titleNode = AceType::DynamicCast<TitleBarNode>(GetTitleBarNode());
524     CHECK_NULL_RETURN(titleNode, nullptr);
525     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetCustomBackButton());
526     if (!backButtonNode) {
527         backButtonNode = AceType::DynamicCast<FrameNode>(titleNode->GetBackButton());
528     }
529     CHECK_NULL_RETURN(backButtonNode, nullptr);
530     AnimationOption transitionOption;
531     transitionOption.SetCurve(Curves::SHARP);
532     auto backButtonNodeContext = backButtonNode->GetRenderContext();
533     CHECK_NULL_RETURN(backButtonNodeContext, nullptr);
534     if (isTransitionIn) {
535         transitionOption.SetDelay(OPACITY_BACKBUTTON_IN_DELAY);
536         transitionOption.SetDuration(OPACITY_BACKBUTTON_IN_DURATION);
537         backButtonNodeContext->SetOpacity(0.0f);
538         return AnimationUtils::StartAnimation(transitionOption,
539             [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
540             auto renderContext = weakRender.Upgrade();
541             CHECK_NULL_VOID(renderContext);
542             renderContext->SetOpacity(1.0f);
543         });
544     }
545     transitionOption.SetDuration(OPACITY_BACKBUTTON_OUT_DURATION);
546     backButtonNodeContext->SetOpacity(1.0f);
547     return AnimationUtils::StartAnimation(transitionOption,
548         [weakRender = WeakPtr<RenderContext>(backButtonNodeContext)]() {
549         auto renderContext = weakRender.Upgrade();
550         CHECK_NULL_VOID(renderContext);
551         renderContext->SetOpacity(0.0f);
552     });
553 }
554 
UpdateTextNodeListAsRenderGroup(bool isPopPage,const RefPtr<NavigationTransitionProxy> & proxy)555 void NavDestinationGroupNode::UpdateTextNodeListAsRenderGroup(
556     bool isPopPage, const RefPtr<NavigationTransitionProxy>& proxy)
557 {
558     if (isPopPage) {
559         CollectTextNodeAsRenderGroup(isPopPage);
560     } else {
561         CHECK_NULL_VOID(proxy);
562         auto pipeline = PipelineContext::GetCurrentContext();
563         CHECK_NULL_VOID(pipeline);
564         pipeline->AddAfterLayoutTask([weakNavDestiniation = WeakClaim(this),
565             weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] () {
566             auto navDestination = weakNavDestiniation.Upgrade();
567             CHECK_NULL_VOID(navDestination);
568             auto proxy = weakProxy.Upgrade();
569             if (proxy && proxy->GetIsFinished()) {
570                 return;
571             }
572             navDestination->CollectTextNodeAsRenderGroup(false);
573         });
574         pipeline->RequestFrame();
575     }
576 }
577 
CollectTextNodeAsRenderGroup(bool isPopPage)578 void NavDestinationGroupNode::CollectTextNodeAsRenderGroup(bool isPopPage)
579 {
580     ReleaseTextNodeList();
581     std::queue<RefPtr<UINode>> childrenLoopQueue;
582     childrenLoopQueue.push(contentNode_);
583 
584     // only the first 50 text nodes will be marked, avoid too much time for traversal
585     // and off-screen drawing at first few frames
586     int32_t remainTextNodeNeedRenderGroup = MAX_RENDER_GROUP_TEXT_NODE_COUNT;
587     while (!childrenLoopQueue.empty() && remainTextNodeNeedRenderGroup > 0) {
588         auto currentNode = childrenLoopQueue.front();
589         childrenLoopQueue.pop();
590         CHECK_NULL_CONTINUE(currentNode);
591         for (auto& child : currentNode->GetChildren()) {
592             if (remainTextNodeNeedRenderGroup <= 0) {
593                 break;
594             }
595             CHECK_NULL_CONTINUE(child);
596             childrenLoopQueue.push(child);
597             auto frameNode = AceType::DynamicCast<FrameNode>(child);
598             if (!frameNode || (frameNode->GetTag() != V2::TEXT_ETS_TAG)) {
599                 continue;
600             }
601             auto layoutProperty = frameNode->GetLayoutProperty<TextLayoutProperty>();
602             if (!layoutProperty ||
603                 (layoutProperty->GetTextOverflowValue(TextOverflow::CLIP) == TextOverflow::MARQUEE)) {
604                 continue;
605             }
606             auto& renderContext = frameNode->GetRenderContext();
607             if (!renderContext || renderContext->GetRenderGroupValue(false)) {
608                 continue;
609             }
610             renderContext->SetMarkNodeGroup(isPopPage ||
611                 (renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT));
612             textNodeList_.emplace_back(WeakPtr<UINode>(child));
613             --remainTextNodeNeedRenderGroup;
614             auto pattern = AceType::DynamicCast<TextPattern>(frameNode->GetPattern());
615             CHECK_NULL_CONTINUE(pattern);
616             pattern->RegisterAfterLayoutCallback([weakRenderContext = WeakPtr<RenderContext>(renderContext)]() {
617                 auto renderContext = weakRenderContext.Upgrade();
618                 if (renderContext && !(renderContext->GetRenderGroupValue(false))) {
619                     renderContext->SetMarkNodeGroup(
620                         renderContext->GetPaintRectWithoutTransform().Height() < MAX_RENDER_GROUP_TEXT_NODE_HEIGHT);
621                 }
622             });
623         }
624     }
625 }
626 
ReleaseTextNodeList()627 void NavDestinationGroupNode::ReleaseTextNodeList()
628 {
629     for (auto& child : textNodeList_) {
630         auto textNode = AceType::DynamicCast<FrameNode>(child.Upgrade());
631         if (!textNode) {
632             continue;
633         }
634         auto pattern = AceType::DynamicCast<TextPattern>(textNode->GetPattern());
635         if (pattern) {
636             pattern->UnRegisterAfterLayoutCallback();
637         }
638         auto renderContext = textNode->GetRenderContext();
639         if (renderContext) {
640             renderContext->SetMarkNodeGroup(renderContext->GetRenderGroupValue(false));
641         }
642     }
643     textNodeList_.clear();
644 }
645 
CleanContent(bool cleanDirectly,bool allowTransition)646 void NavDestinationGroupNode::CleanContent(bool cleanDirectly, bool allowTransition)
647 {
648     // cacheNode is cached for pip info, and is no need to clean when clean content node
649     if (IsCacheNode()) {
650         return;
651     }
652     auto pattern = GetPattern<NavDestinationPattern>();
653     CHECK_NULL_VOID(pattern);
654     auto shallowBuilder = pattern->GetShallowBuilder();
655     if (shallowBuilder) {
656         shallowBuilder->MarkIsExecuteDeepRenderDone(false);
657     }
658     if (GetContentNode()) {
659         GetContentNode()->Clean(cleanDirectly, allowTransition);
660     }
661 }
662 
IsNodeInvisible(const RefPtr<FrameNode> & node)663 bool NavDestinationGroupNode::IsNodeInvisible(const RefPtr<FrameNode>& node)
664 {
665     auto navigaiton = DynamicCast<NavigationGroupNode>(node);
666     CHECK_NULL_RETURN(navigaiton, false);
667     int32_t lastStandardIndex = navigaiton->GetLastStandardIndex();
668     bool isInvisible = index_ < lastStandardIndex;
669     return isInvisible;
670 }
671 
ToDumpString()672 std::string NavDestinationGroupNode::ToDumpString()
673 {
674     std::string dumpString;
675     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
676     CHECK_NULL_RETURN(navDestinationPattern, dumpString);
677     dumpString.append("| [");
678     dumpString.append(std::to_string(index_));
679     dumpString.append("]{ ID: ");
680     dumpString.append(std::to_string(navDestinationPattern->GetNavDestinationId()));
681     dumpString.append(", Name: \"");
682     dumpString.append(navDestinationPattern->GetName());
683     dumpString.append("\", Mode: \"");
684     dumpString.append(mode_ == NavDestinationMode::STANDARD ? "STANDARD" : "DIALOG");
685     dumpString.append("\", IsOnShow: \"");
686     dumpString.append(navDestinationPattern->GetIsOnShow() ? "TRUE" : "FALSE");
687     dumpString.append("\" }");
688     return dumpString;
689 }
690 
DoTransition(NavigationOperation operation,bool isEnter)691 int32_t NavDestinationGroupNode::DoTransition(NavigationOperation operation, bool isEnter)
692 {
693     if (navDestinationTransitionDelegate_) {
694         return DoCustomTransition(operation, isEnter);
695     }
696     return DoSystemTransition(operation, isEnter);
697 }
698 
DoSystemTransition(NavigationOperation operation,bool isEnter)699 int32_t NavDestinationGroupNode::DoSystemTransition(NavigationOperation operation, bool isEnter)
700 {
701     auto noneSystemTransition = NavigationSystemTransitionType::NONE;
702     if ((systemTransitionType_ & NavigationSystemTransitionType::FADE) != noneSystemTransition) {
703         return DoSystemFadeTransition(isEnter);
704     }
705     if ((systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT) != noneSystemTransition ||
706         (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_BOTTOM) != noneSystemTransition) {
707         return DoSystemSlideTransition(operation, isEnter);
708     }
709     if ((systemTransitionType_ & NavigationSystemTransitionType::EXPLODE) != noneSystemTransition) {
710         return isEnter ? DoSystemEnterExplodeTransition(operation) : DoSystemExitExplodeTransition(operation);
711     }
712     return INVALID_ANIMATION_ID;
713 }
714 
DoSystemFadeTransition(bool isEnter)715 int32_t NavDestinationGroupNode::DoSystemFadeTransition(bool isEnter)
716 {
717     auto renderContext = GetRenderContext();
718     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
719     auto eventHub = GetEventHub<EventHub>();
720     if (!inCurrentStack_ && eventHub) {
721         eventHub->SetEnabledInternal(false);
722     }
723     animationId_ = MakeUniqueAnimationId();
724     SetIsOnAnimation(true);
725     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
726         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DURATION : SYSTEM_EXIT_FADE_TRANSITION_DURATION,
727         isEnter ? SYSTEM_ENTER_FADE_TRANSITION_DELAY : SYSTEM_EXIT_FADE_TRANSITION_DELAY);
728     renderContext->OpacityAnimation(option, isEnter ? 0.0f : 1.0f, isEnter ? 1.0f : 0.0f);
729     return animationId_;
730 }
731 
DoSystemSlideTransition(NavigationOperation operation,bool isEnter)732 int32_t NavDestinationGroupNode::DoSystemSlideTransition(NavigationOperation operation, bool isEnter)
733 {
734     auto eventHub = GetEventHub<EventHub>();
735     if (!inCurrentStack_ && eventHub) {
736         eventHub->SetEnabledInternal(false);
737     }
738     animationId_ = MakeUniqueAnimationId();
739     SetIsOnAnimation(true);
740     if ((operation == NavigationOperation::POP) ^ isEnter) {
741         // translate animation
742         bool isRight = (systemTransitionType_ & NavigationSystemTransitionType::SLIDE_RIGHT)
743             != NavigationSystemTransitionType::NONE;
744         std::function<void()> translateEvent = [weak = WeakClaim(this), isEnter, isRight, operation]() {
745             auto navDestination = weak.Upgrade();
746             CHECK_NULL_VOID(navDestination);
747             auto renderContext = navDestination->GetRenderContext();
748             CHECK_NULL_VOID(renderContext);
749             if (!isEnter) {
750                 auto frameSize = navDestination->GetGeometryNode()->GetFrameSize();
751                 renderContext->UpdateTranslateInXY(
752                     { isRight ? frameSize.Width() : 0.0f, isRight ? 0.0f : frameSize.Height() });
753             } else {
754                 renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
755             }
756         };
757         RefPtr<Curve> curve = isRight ? MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 342.0f, 37.0f)
758             : MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
759         auto option = BuildAnimationOption(curve, BuildTransitionFinishCallback());
760         if (!isEnter) {
761             GetRenderContext()->UpdateTranslateInXY({ 0.0f, 0.0f });
762         } else {
763             auto frameSize = GetGeometryNode()->GetFrameSize();
764             GetRenderContext()->UpdateTranslateInXY(
765                 { isRight ? frameSize.Width() : 0.0f, isRight ? 0.0f : frameSize.Height() });
766         }
767         AnimationUtils::Animate(option, translateEvent, option.GetOnFinishEvent());
768     } else {
769         // mask animation
770         auto option = BuildAnimationOption(
771             Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_SLIDE_TRANSITION_MASK_DURATION);
772         auto beginColor = isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
773         auto endColor = !isEnter ? SLIDE_ANIMATION_MASK_COLOR : Color::TRANSPARENT;
774         DoMaskAnimation(option, beginColor, endColor);
775     }
776     return animationId_;
777 }
778 
779 
DoSystemEnterExplodeTransition(NavigationOperation operation)780 int32_t NavDestinationGroupNode::DoSystemEnterExplodeTransition(NavigationOperation operation)
781 {
782     auto renderContext = GetRenderContext();
783     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
784     auto eventHub = GetEventHub<EventHub>();
785     if (!inCurrentStack_ && eventHub) {
786         eventHub->SetEnabledInternal(false);
787     }
788     animationId_ = MakeUniqueAnimationId();
789     SetIsOnAnimation(true);
790     if (operation == NavigationOperation::POP) {
791         // mask animation
792         DoMaskAnimation(BuildAnimationOption(Curves::FRICTION, nullptr, SYSTEM_EXPLODE_TRANSITION_MASK_DURATION),
793             SLIDE_ANIMATION_MASK_COLOR, Color::TRANSPARENT);
794         // opacity animation
795         auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
796             SYSTEM_ENTER_POP_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_POP_EXPLODE_OPACITY_DELAY);
797         renderContext->OpacityAnimation(option, 0.0f, 1.0f);
798         return animationId_;
799     }
800     // opacity animation
801     auto option = BuildAnimationOption(Curves::SHARP, BuildTransitionFinishCallback(),
802         SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DURATION, SYSTEM_ENTER_PUSH_EXPLODE_OPACITY_DELAY);
803     renderContext->OpacityAnimation(option, 0.0f, 1.0f);
804     // scale animation for enter-push
805     auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
806     renderContext->ScaleAnimation(
807         BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback()), 0.75f, 1.0f);
808     return animationId_;
809 }
810 
DoSystemExitExplodeTransition(NavigationOperation operation)811 int32_t NavDestinationGroupNode::DoSystemExitExplodeTransition(NavigationOperation operation)
812 {
813     auto renderContext = GetRenderContext();
814     CHECK_NULL_RETURN(renderContext, INVALID_ANIMATION_ID);
815     auto eventHub = GetEventHub<EventHub>();
816     if (!inCurrentStack_ && eventHub) {
817         eventHub->SetEnabledInternal(false);
818     }
819     animationId_ = MakeUniqueAnimationId();
820     SetIsOnAnimation(true);
821     if (operation == NavigationOperation::POP) {
822         // opacity animation
823         renderContext->OpacityAnimation(
824             BuildAnimationOption(Curves::SHARP, nullptr, SYSTEM_EXIT_POP_EXPLODE_OPACITY_DURATION), 1.0f, 0.0f);
825         // scale animation
826         auto scaleCurve = MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 328.0f, 36.0f);
827         auto option = BuildAnimationOption(scaleCurve, BuildTransitionFinishCallback());
828         renderContext->ScaleAnimation(option, 1.0f, 0.8f);
829         return animationId_;
830     }
831     // opacity animation
832     renderContext->OpacityAnimation(
833         BuildAnimationOption(Curves::SHARP, nullptr, SYSTEM_EXIT_PUSH_EXPLODE_OPACITY_DELAY), 1.0f, 0.0f);
834     // mask animation
835     auto maskOption = BuildAnimationOption(
836         Curves::FRICTION, BuildTransitionFinishCallback(), SYSTEM_EXPLODE_TRANSITION_MASK_DURATION);
837     DoMaskAnimation(maskOption, Color::TRANSPARENT, SLIDE_ANIMATION_MASK_COLOR);
838     return animationId_;
839 }
840 
DoMaskAnimation(const AnimationOption & option,Color begin,Color end)841 void NavDestinationGroupNode::DoMaskAnimation(const AnimationOption& option, Color begin, Color end)
842 {
843     auto renderContext = GetRenderContext();
844     CHECK_NULL_VOID(renderContext);
845     std::function<void()> maskEvent = [weak = WeakClaim(this), end]() {
846         auto navDestination = weak.Upgrade();
847         CHECK_NULL_VOID(navDestination);
848         auto renderContext = navDestination->GetRenderContext();
849         CHECK_NULL_VOID(renderContext);
850         renderContext->SetActualForegroundColor(end);
851     };
852 
853     // initial property
854     renderContext->SetActualForegroundColor(begin);
855     AnimationUtils::Animate(option, maskEvent, option.GetOnFinishEvent());
856 }
857 
DoCustomTransition(NavigationOperation operation,bool isEnter)858 int32_t NavDestinationGroupNode::DoCustomTransition(NavigationOperation operation, bool isEnter)
859 {
860     auto delegate = navDestinationTransitionDelegate_;
861     if (!delegate) {
862         return INVALID_ANIMATION_ID;
863     }
864     auto eventHub = GetEventHub<EventHub>();
865     if (!inCurrentStack_ && eventHub) {
866         eventHub->SetEnabledInternal(false);
867     }
868     auto allTransitions = delegate(operation, isEnter);
869     if (!allTransitions.has_value()) {
870         return INVALID_ANIMATION_ID;
871     }
872     int32_t longestAnimationDuration = INT32_MIN;
873     for (auto transition: allTransitions.value()) {
874         if (transition.duration + transition.delay > longestAnimationDuration) {
875             longestAnimationDuration = transition.duration + transition.delay;
876         }
877     }
878     if (longestAnimationDuration != INT32_MIN) {
879         SetIsOnAnimation(true);
880     } else {
881         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "navDestination custom transition array is empty!");
882     }
883     auto pipeline = GetContext();
884     CHECK_NULL_RETURN(pipeline, INVALID_ANIMATION_ID);
885     pipeline->FlushBuild();
886     pipeline->FlushUITasks();
887     animationId_ = MakeUniqueAnimationId();
888     bool hasRest = false;
889     for (auto transition: allTransitions.value()) {
890         StartCustomTransitionAnimation(transition, isEnter, hasRest, longestAnimationDuration);
891     }
892     return animationId_;
893 }
894 
StartCustomTransitionAnimation(NavDestinationTransition & transition,bool isEnter,bool & hasResetProperties,int32_t longestAnimationDuration)895 void NavDestinationGroupNode::StartCustomTransitionAnimation(NavDestinationTransition& transition,
896     bool isEnter, bool& hasResetProperties, int32_t longestAnimationDuration)
897 {
898     AnimationOption option;
899     option.SetDuration(transition.duration);
900     option.SetCurve(transition.curve);
901     option.SetDelay(transition.delay);
902 
903     std::function<void()> event =
904         [transitionEvent = std::move(transition.event), weak = WeakClaim(this), isEnter, &hasResetProperties]() {
905             // do necessary system-side tasks
906             auto navDestination = weak.Upgrade();
907             CHECK_NULL_VOID(navDestination);
908             if (!hasResetProperties && isEnter) {
909                 auto pattern = navDestination->GetPattern<NavDestinationPattern>();
910                 CHECK_NULL_VOID(pattern);
911                 auto navigation = AceType::DynamicCast<NavigationGroupNode>(pattern->GetNavigationNode());
912                 if (navigation) {
913                     /*
914                     *  Reset the system animation properties in custom transition
915                     *  animation closure to prevent animation mutation.
916                     */
917                     navigation->ResetSystemAnimationProperties(navDestination);
918                 }
919                 hasResetProperties = true;
920             }
921             // do user-set task
922             transitionEvent();
923             auto pipeline = navDestination->GetContext();
924             CHECK_NULL_VOID(pipeline);
925             pipeline->FlushBuild();
926             pipeline->FlushUITasks();
927         };
928     // only do remove or set visibility in longest custom transition animation's finish callback.
929     std::function<void()> finish = transition.duration + transition.delay == longestAnimationDuration ?
930         BuildTransitionFinishCallback(false, std::move(transition.onTransitionEnd)) :
931         std::move(transition.onTransitionEnd);
932     AnimationUtils::Animate(option, event, finish);
933     auto pattern = GetPattern<NavDestinationPattern>();
934     CHECK_NULL_VOID(pattern);
935     TAG_LOGI(AceLogTag::ACE_NAVIGATION,
936         "%{public}s trigger custom transition, duration: %{public}d, delay: %{public}d, curve: %{public}s",
937         pattern->GetName().c_str(), transition.duration, transition.delay, transition.curve->ToString().c_str());
938 }
939 
MakeUniqueAnimationId()940 int32_t NavDestinationGroupNode::MakeUniqueAnimationId()
941 {
942     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
943     CHECK_NULL_RETURN(navDestinationPattern, INVALID_ANIMATION_ID);
944     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
945     CHECK_NULL_RETURN(navigationNode, INVALID_ANIMATION_ID);
946     return navigationNode->MakeUniqueAnimationId();
947 }
948 
BuildTransitionFinishCallback(bool isSystemTransition,std::function<void ()> && extraOption)949 std::function<void()> NavDestinationGroupNode::BuildTransitionFinishCallback(
950     bool isSystemTransition, std::function<void()>&& extraOption)
951 {
952     std::function<void()> finish = [extraOption = std::move(extraOption), weak = WeakClaim(this),
953         animationId = animationId_, isSystemTransition]() {
954             auto navDestination = weak.Upgrade();
955             CHECK_NULL_VOID(navDestination);
956             auto destinationPattern = navDestination->GetPattern<NavDestinationPattern>();
957             CHECK_NULL_VOID(destinationPattern);
958             TAG_LOGI(AceLogTag::ACE_NAVIGATION, "%{public}s transition finish", destinationPattern->GetName().c_str());
959             // do extraOption first
960             if (extraOption) {
961                 extraOption();
962             }
963             // do necessary system-side tasks
964             if (animationId != navDestination->GetAnimationId()) {
965                 return;
966             }
967             if (isSystemTransition) {
968                 navDestination->ResetCustomTransitionAnimationProperties();
969             }
970             // only handle current node in latest finish callback.
971             if (!navDestination->GetInCurrentStack()) {
972                 // can't be reused means it is not in navigation stack anymore, so remove it.
973                 navDestination->CleanContent();
974                 auto parent = navDestination->GetParent();
975                 CHECK_NULL_VOID(parent);
976                 parent->RemoveChild(navDestination);
977                 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
978             } else if (navDestination->HasStandardBefore()) {
979                 navDestination->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
980                 navDestination->SetJSViewActive(false);
981             }
982             navDestination->SetIsOnAnimation(false);
983         };
984     return finish;
985 }
986 
HasStandardBefore() const987 bool NavDestinationGroupNode::HasStandardBefore() const
988 {
989     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
990     CHECK_NULL_RETURN(navDestinationPattern, false);
991     auto navigationNode =
992         AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
993     CHECK_NULL_RETURN(navigationNode, false);
994     return index_ < navigationNode->GetLastStandardIndex();
995 }
996 
ResetCustomTransitionAnimationProperties()997 void NavDestinationGroupNode::ResetCustomTransitionAnimationProperties()
998 {
999     auto renderContext = GetRenderContext();
1000     CHECK_NULL_VOID(renderContext);
1001     renderContext->UpdateTranslateInXY({ 0.0f, 0.0f });
1002     renderContext->SetOpacity(userSetOpacity_);
1003     renderContext->SetActualForegroundColor(Color::TRANSPARENT);
1004 }
1005 
GetNavigationNode()1006 RefPtr<UINode> NavDestinationGroupNode::GetNavigationNode()
1007 {
1008     auto navDestinationPattern = GetPattern<NavDestinationPattern>();
1009     CHECK_NULL_RETURN(navDestinationPattern, nullptr);
1010     return navDestinationPattern->GetNavigationNode();
1011 }
1012 } // namespace OHOS::Ace::NG
1013