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