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