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/navigation/navigation_pattern.h"
17 #include <string>
18
19 #include "base/geometry/dimension.h"
20 #include "base/log/dump_log.h"
21 #include "base/perfmonitor/perf_constants.h"
22 #include "base/perfmonitor/perf_monitor.h"
23 #include "core/common/container.h"
24 #include "core/common/manager_interface.h"
25 #include "core/components_ng/pattern/navigation/nav_bar_layout_property.h"
26 #include "core/components_ng/pattern/navigation/nav_bar_node.h"
27 #include "core/components_ng/pattern/navigation/navigation_model_data.h"
28 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
29 #include "core/components_ng/pattern/stage/page_pattern.h"
30 #include "core/components_ng/pattern/text_field/text_field_manager.h"
31
32 namespace OHOS::Ace::NG {
33
34 constexpr int32_t NAVIMODE_CHANGE_ANIMATION_DURATION = 250;
35 constexpr int32_t OPACITY_ANIMATION_DURATION_APPEAR = 150;
36 constexpr int32_t OPACITY_ANIMATION_DURATION_DISAPPEAR = 250;
37 constexpr int32_t EMPTY_DESTINATION_CHILD_SIZE = 1;
38 constexpr Dimension DEFAULT_DRAG_REGION = 12.0_vp;
39 constexpr float DEFAULT_HALF = 2.0f;
40 const Color MASK_COLOR = Color::FromARGB(25, 0, 0, 0);
41 namespace {
42
43 constexpr static int32_t PLATFORM_VERSION_TEN = 10;
44
45 } // namespace
46
NavigationPattern()47 NavigationPattern::NavigationPattern()
48 {
49 navigationController_ = std::make_shared<InnerNavigationController>(WeakClaim(this));
50 }
51
GetTitleBarRenderContext()52 RefPtr<RenderContext> NavigationPattern::GetTitleBarRenderContext()
53 {
54 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
55 CHECK_NULL_RETURN(hostNode, nullptr);
56 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
57 CHECK_NULL_RETURN(layoutProperty, nullptr);
58 auto contentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
59 CHECK_NULL_RETURN(contentNode, nullptr);
60 if (contentNode->FindChildNodeOfClass<NavDestinationGroupNode>()) {
61 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
62 CHECK_NULL_RETURN(navBarNode, nullptr);
63 auto renderContext = navBarNode->GetRenderContext();
64 return renderContext;
65 } else {
66 auto renderContext = contentNode->GetRenderContext();
67 return renderContext;
68 }
69 }
70
DoAnimation(NavigationMode usrNavigationMode)71 void NavigationPattern::DoAnimation(NavigationMode usrNavigationMode)
72 {
73 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
74 CHECK_NULL_VOID(hostNode);
75 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
76 CHECK_NULL_VOID(layoutProperty);
77
78 auto context = PipelineContext::GetCurrentContext();
79 CHECK_NULL_VOID(context);
80 layoutProperty->UpdateNavigationMode(navigationMode_);
81 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
82 AnimationOption option = AnimationOption();
83 option.SetDuration(NAVIMODE_CHANGE_ANIMATION_DURATION);
84 option.SetCurve(Curves::FRICTION);
85 option.SetFillMode(FillMode::FORWARDS);
86 AnimationOption optionAlpha = AnimationOption();
87 optionAlpha.SetCurve(Curves::SHARP);
88 optionAlpha.SetFillMode(FillMode::FORWARDS);
89 auto renderContext = GetTitleBarRenderContext();
90 CHECK_NULL_VOID(renderContext);
91
92 std::function<void()> finishCallback = [optionAlpha, renderContext, hostNode]() {
93 renderContext->OpacityAnimation(optionAlpha, 0, 1);
94 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
95 };
96
97 context->OpenImplicitAnimation(option, option.GetCurve(), finishCallback);
98 layoutProperty->UpdateNavigationMode(usrNavigationMode);
99 hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
100 context->FlushUITasks();
101 if (usrNavigationMode == NavigationMode::STACK || navigationMode_ == NavigationMode::SPLIT) {
102 optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_DISAPPEAR);
103 renderContext->OpacityAnimation(optionAlpha, 1, 0);
104 } else if (usrNavigationMode == NavigationMode::SPLIT || navigationMode_ == NavigationMode::STACK) {
105 optionAlpha.SetDuration(OPACITY_ANIMATION_DURATION_APPEAR);
106 renderContext->OpacityAnimation(optionAlpha, 0, 1);
107 }
108 context->CloseImplicitAnimation();
109 navigationMode_ = usrNavigationMode;
110 }
111
OnAttachToFrameNode()112 void NavigationPattern::OnAttachToFrameNode()
113 {
114 auto host = GetHost();
115 CHECK_NULL_VOID(host);
116 auto pipelineContext = PipelineContext::GetCurrentContext();
117 CHECK_NULL_VOID(pipelineContext);
118 pipelineContext->AddWindowStateChangedCallback(host->GetId());
119 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
120 CHECK_NULL_VOID(navigationNode);
121 auto stageManager = pipelineContext->GetStageManager();
122 CHECK_NULL_VOID(stageManager);
123 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
124 CHECK_NULL_VOID(pageNode);
125 auto pagePattern = pageNode->GetPattern<PagePattern>();
126 CHECK_NULL_VOID(pagePattern);
127 CHECK_NULL_VOID(pagePattern->GetPageInfo());
128 int32_t pageId = pagePattern->GetPageInfo()->GetPageId();
129
130 // when use router, onShowCallback will be called when page show
131 std::function<void()> onShowCallback = [weakNavigationNode = WeakPtr<NavigationGroupNode>(navigationNode),
132 pageId]() {
133 auto pipelineContext = PipelineContext::GetCurrentContext();
134 CHECK_NULL_VOID(pipelineContext);
135 auto navigationNode = weakNavigationNode.Upgrade();
136 CHECK_NULL_VOID(navigationNode);
137 pipelineContext->AddWindowStateChangedCallback(navigationNode->GetId());
138 auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
139 CHECK_NULL_VOID(navigationPattern);
140 CHECK_NULL_VOID(navigationPattern->navigationStack_);
141 navigationPattern->NotifyDialogChange(true, false);
142 };
143 pipelineContext->AddNavigationStateCallback(pageId, navigationNode->GetId(), onShowCallback, true);
144 // when use router, onShowCallback will be called when page hide
145 std::function<void()> onHideCallback = [weakNavigationNode = WeakPtr<NavigationGroupNode>(navigationNode)]() {
146 auto pipelineContext = PipelineContext::GetCurrentContext();
147 CHECK_NULL_VOID(pipelineContext);
148 auto navigationNode = weakNavigationNode.Upgrade();
149 CHECK_NULL_VOID(navigationNode);
150 pipelineContext->RemoveWindowStateChangedCallback(navigationNode->GetId());
151 auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
152 CHECK_NULL_VOID(navigationPattern);
153 navigationPattern->SyncWithJsStackIfNeeded();
154 CHECK_NULL_VOID(navigationPattern->navigationStack_);
155 navigationPattern->NotifyDialogChange(false, false);
156 };
157 pipelineContext->AddNavigationStateCallback(pageId, navigationNode->GetId(), onHideCallback, false);
158 auto theme = NavigationGetTheme();
159 if (theme && theme->GetNavBarUnfocusEffectEnable()) {
160 pipelineContext->AddWindowFocusChangedCallback(host->GetId());
161 }
162
163 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
164 SafeAreaExpandOpts opts = {.type = SAFE_AREA_TYPE_SYSTEM, .edges = SAFE_AREA_EDGE_ALL};
165 host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
166 }
167 }
168
OnDetachFromFrameNode(FrameNode * frameNode)169 void NavigationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
170 {
171 auto id = frameNode->GetId();
172 auto pipeline = AceType::DynamicCast<PipelineContext>(PipelineBase::GetCurrentContext());
173 CHECK_NULL_VOID(pipeline);
174 pipeline->RemoveWindowStateChangedCallback(id);
175 }
176
OnModifyDone()177 void NavigationPattern::OnModifyDone()
178 {
179 // !!! Do not add operations about NavPathStack here, see @SyncWithJsStackIfNeeded
180 Pattern::OnModifyDone();
181 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
182 CHECK_NULL_VOID(hostNode);
183 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
184 CHECK_NULL_VOID(navBarNode);
185 navBarNode->MarkModifyDone();
186
187 auto pipeline = PipelineContext::GetCurrentContext();
188 CHECK_NULL_VOID(pipeline);
189 auto currentPlatformVersion = pipeline->GetMinPlatformVersion();
190 if (currentPlatformVersion >= PLATFORM_VERSION_TEN) {
191 auto dividerNode = GetDividerNode();
192 CHECK_NULL_VOID(dividerNode);
193 auto gestureHub = dividerNode->GetOrCreateGestureEventHub();
194 CHECK_NULL_VOID(gestureHub);
195 InitDragEvent(gestureHub);
196 auto inputHub = dividerNode->GetOrCreateInputEventHub();
197 CHECK_NULL_VOID(inputHub);
198 InitDividerMouseEvent(inputHub);
199 }
200 auto&& opts = hostNode->GetLayoutProperty()->GetSafeAreaExpandOpts();
201 if (opts && opts->Expansive()) {
202 navBarNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(*opts);
203 navBarNode->MarkModifyDone();
204
205 auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
206 CHECK_NULL_VOID(navigationContentNode);
207 navigationContentNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(*opts);
208 navigationContentNode->MarkModifyDone();
209
210 auto dividerNode = AceType::DynamicCast<FrameNode>(hostNode->GetDividerNode());
211 CHECK_NULL_VOID(dividerNode);
212 dividerNode->GetLayoutProperty()->UpdateSafeAreaExpandOpts(*opts);
213 dividerNode->MarkModifyDone();
214 }
215 }
216
SyncWithJsStackIfNeeded()217 void NavigationPattern::SyncWithJsStackIfNeeded()
218 {
219 if (!needSyncWithJsStack_) {
220 return;
221 }
222
223 needSyncWithJsStack_ = false;
224 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "sync with js stack");
225 UpdateNavPathList();
226 RefreshNavDestination();
227 }
228
UpdateNavPathList()229 void NavigationPattern::UpdateNavPathList()
230 {
231 CHECK_NULL_VOID(navigationStack_);
232 navigationStack_->UpdateRemovedNavPathList(); // Delete Removed NavPathList
233 auto preTopNavPath = navigationStack_->GetPreTopNavPath();
234 auto pathNames = navigationStack_->GetAllPathName();
235 auto cacheNodes = navigationStack_->GetAllCacheNodes();
236 preTopNavPath_ = preTopNavPath;
237 preStackSize_ = navigationStack_->PreSize();
238 NavPathList navPathList;
239 auto replaceValue = navigationStack_->GetReplaceValue();
240 for (size_t i = 0; i < pathNames.size(); ++i) {
241 auto pathName = pathNames[i];
242 RefPtr<UINode> uiNode = navigationStack_->Get(pathName);
243 auto isSameWithLast = (i == pathNames.size() - 1) && (replaceValue == 1);
244 if (uiNode) {
245 navigationStack_->RemoveInNavPathList(pathName, uiNode);
246 navigationStack_->RemoveInPreNavPathList(pathName, uiNode);
247 if (isSameWithLast) {
248 uiNode = GenerateUINodeByIndex(static_cast<int32_t>(i));
249 }
250 navPathList.emplace_back(std::make_pair(pathName, uiNode));
251 continue;
252 }
253 uiNode = navigationStack_->GetFromPreBackup(pathName);
254 if (uiNode) {
255 navigationStack_->RemoveInPreNavPathList(pathName, uiNode);
256 if (isSameWithLast) {
257 uiNode = GenerateUINodeByIndex(static_cast<int32_t>(i));
258 }
259 navPathList.emplace_back(std::make_pair(pathName, uiNode));
260 continue;
261 }
262 uiNode = navigationStack_->GetFromCacheNode(cacheNodes, pathName);
263 if (uiNode) {
264 navPathList.emplace_back(std::make_pair(pathName, uiNode));
265 navigationStack_->RemoveCacheNode(cacheNodes, pathName, uiNode);
266 continue;
267 }
268 uiNode = GenerateUINodeByIndex(static_cast<int32_t>(i));
269 navPathList.emplace_back(std::make_pair(pathName, uiNode));
270 }
271 navigationStack_->ClearPreBuildNodeList();
272 navigationStack_->SetNavPathList(navPathList);
273 }
274
RefreshNavDestination()275 void NavigationPattern::RefreshNavDestination()
276 {
277 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
278 CHECK_NULL_VOID(hostNode);
279 int32_t preSize = preStackSize_;
280 auto preTopNavPath = std::move(preTopNavPath_);
281 auto& navPathList = navigationStack_->GetAllNavDestinationNodes();
282 hostNode->UpdateNavDestinationNodeWithoutMarkDirty(
283 preTopNavPath.has_value() ? preTopNavPath->second : nullptr, navigationModeChange_);
284 auto newTopNavPath = navigationStack_->GetTopNavPath();
285 auto size = navigationStack_->Size();
286 CheckTopNavPathChange(preTopNavPath, newTopNavPath, preSize > size);
287
288 /* if first navDestination is removed, the new one will be refreshed */
289 if (!navPathList.empty()) {
290 auto firstNavDesNode = AceType::DynamicCast<NavDestinationGroupNode>(
291 NavigationGroupNode::GetNavDestinationNode(navPathList.front().second));
292 CHECK_NULL_VOID(firstNavDesNode);
293 firstNavDesNode->MarkModifyDone();
294 }
295
296 preStackSize_ = 0;
297 }
298
CheckTopNavPathChange(const std::optional<std::pair<std::string,RefPtr<UINode>>> & preTopNavPath,const std::optional<std::pair<std::string,RefPtr<UINode>>> & newTopNavPath,bool isPopPage)299 void NavigationPattern::CheckTopNavPathChange(
300 const std::optional<std::pair<std::string, RefPtr<UINode>>>& preTopNavPath,
301 const std::optional<std::pair<std::string, RefPtr<UINode>>>& newTopNavPath, bool isPopPage)
302 {
303 auto replaceValue = navigationStack_->GetReplaceValue();
304 if (preTopNavPath == newTopNavPath && replaceValue != 1) {
305 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "page is not change. don't transition");
306 if (currentProxy_) {
307 currentProxy_->SetIsSuccess(false);
308 }
309 return;
310 }
311
312 // close keyboard
313 #if defined(ENABLE_STANDARD_INPUT)
314 auto pipeline = PipelineContext::GetCurrentContext();
315 CHECK_NULL_VOID(pipeline);
316 auto textfieldManager = DynamicCast<TextFieldManagerNG>(pipeline->GetTextFieldManager());
317 if (textfieldManager) {
318 textfieldManager->ProcessNavKeyboard();
319 }
320 #endif
321
322 isChanged_ = true;
323 if (replaceValue == 1) {
324 const int32_t replaceAnimation = 2;
325 navigationStack_->UpdateReplaceValue(replaceAnimation);
326 }
327 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
328 CHECK_NULL_VOID(hostNode);
329 auto contentNode = hostNode->GetContentNode();
330 CHECK_NULL_VOID(contentNode);
331 auto context = PipelineContext::GetCurrentContext();
332 CHECK_NULL_VOID(context);
333 // fire onHidden and lostFocus event
334 RefPtr<NavDestinationGroupNode> preTopNavDestination;
335 int32_t lastPreIndex = -1;
336 if (preTopNavPath.has_value()) {
337 // pre page is not in the current stack
338 lastPreIndex = navigationStack_->FindIndex(preTopNavPath->first, preTopNavPath->second, true);
339 isPopPage |= lastPreIndex == -1;
340 preTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
341 NavigationGroupNode::GetNavDestinationNode(preTopNavPath->second));
342 if (preTopNavDestination) {
343 auto navDestinationPattern =
344 AceType::DynamicCast<NavDestinationPattern>(preTopNavDestination->GetPattern());
345 CHECK_NULL_VOID(navDestinationPattern);
346 if (navDestinationPattern->GetIsOnShow()) {
347 auto eventHub = preTopNavDestination->GetEventHub<NavDestinationEventHub>();
348 CHECK_NULL_VOID(eventHub);
349 NotifyPageHide(preTopNavPath->first);
350 }
351 auto focusHub = preTopNavDestination->GetOrCreateFocusHub();
352 focusHub->SetParentFocusable(false);
353 focusHub->LostFocus();
354 }
355 } else {
356 // navBar to new top page case
357 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
358 CHECK_NULL_VOID(navBarNode);
359 auto focusHub = navBarNode->GetOrCreateFocusHub();
360 focusHub->LostFocus();
361 }
362 RefPtr<NavDestinationGroupNode> newTopNavDestination;
363 // fire onShown and requestFocus Event
364 if (newTopNavPath.has_value()) {
365 newTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
366 NavigationGroupNode::GetNavDestinationNode(newTopNavPath->second));
367 if (newTopNavDestination) {
368 auto navDestinationPattern =
369 AceType::DynamicCast<NavDestinationPattern>(newTopNavDestination->GetPattern());
370 CHECK_NULL_VOID(navDestinationPattern);
371 if (!navDestinationPattern->GetIsOnShow()) {
372 NotifyPageShow(newTopNavPath->first);
373 }
374 auto focusHub = newTopNavDestination->GetOrCreateFocusHub();
375 context->AddAfterLayoutTask([focusHub]() {
376 focusHub->SetParentFocusable(true);
377 focusHub->RequestFocus();
378 });
379 }
380 } else {
381 // back to navBar case
382 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
383 CHECK_NULL_VOID(navBarNode);
384 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(
385 hostNode->GetLayoutProperty());
386 if (!navigationLayoutProperty->GetHideNavBarValue(false)) {
387 navBarNode->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
388 navBarNode->SetJSViewActive(true);
389 }
390 auto stageManager = context->GetStageManager();
391 if (stageManager != nullptr) {
392 RefPtr<FrameNode> pageNode = stageManager->GetLastPage();
393 CHECK_NULL_VOID(pageNode);
394 auto pagePattern = pageNode->GetPattern<NG::PagePattern>();
395 if (pagePattern != nullptr) {
396 auto pageInfo = pagePattern->GetPageInfo();
397 NotifyPageShow(pageInfo->GetPageUrl());
398 }
399 }
400 navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
401 auto focusHub = navBarNode->GetOrCreateFocusHub();
402 focusHub->RequestFocus();
403 }
404 bool isShow = false;
405 bool isDialog =
406 (preTopNavDestination && preTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG) ||
407 (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::DIALOG);
408 if (preTopNavDestination) {
409 if (isDialog) {
410 auto lastStandardIndex = hostNode->GetLastStandardIndex();
411 isShow = (lastPreIndex != -1) && (lastPreIndex >= lastStandardIndex);
412 hostNode->SetNeedSetInvisible(lastStandardIndex >= 0);
413 if (lastStandardIndex < 0) {
414 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
415 auto layoutProperty = navBarNode->GetLayoutProperty();
416 layoutProperty->UpdateVisibility(VisibleType::VISIBLE, true);
417 navBarNode->SetJSViewActive(true);
418 }
419 }
420 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(preTopNavDestination->GetPattern());
421 CHECK_NULL_VOID(navDestinationPattern);
422 if (navDestinationPattern->GetIsOnShow() && !isShow) {
423 auto eventHub = preTopNavDestination->GetEventHub<NavDestinationEventHub>();
424 CHECK_NULL_VOID(eventHub);
425 NotifyPageHide(preTopNavPath->first);
426 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
427 navDestinationPattern->SetIsOnShow(false);
428 // The navigations in NavDestination should be fired the hidden event
429 NavigationPattern::FireNavigationStateChange(preTopNavDestination, false);
430 }
431 }
432 bool disableAllAnimation = navigationStack_->GetDisableAnimation();
433 bool animated = navigationStack_->GetAnimatedValue();
434 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
435 "transition start, disableAllAnimation: %{public}d, animated: %{public}d, isPopPage: %{public}d",
436 disableAllAnimation, animated, isPopPage);
437 if (isDialog) {
438 // dialog navDestination no need transition animation.
439 TransitionWithOutAnimation(preTopNavDestination, newTopNavDestination, isPopPage, isShow);
440 hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
441 return;
442 }
443 if (disableAllAnimation || !animated) {
444 // transition without animation need to run before layout for geometryTransition.
445 TransitionWithOutAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
446 navigationStack_->UpdateAnimatedValue(true);
447 } else {
448 // before the animation of navDes replacing, update the zIndex of the previous navDes node
449 UpdatePreNavDesZIndex(preTopNavDestination, newTopNavDestination);
450 // transition with animation need to run after layout task
451 context->AddAfterLayoutTask(
452 [preTopNavDestination, newTopNavDestination, isPopPage, weakNavigationPattern = WeakClaim(this)]() {
453 auto navigationPattern = weakNavigationPattern.Upgrade();
454 CHECK_NULL_VOID(navigationPattern);
455 navigationPattern->TransitionWithAnimation(preTopNavDestination, newTopNavDestination, isPopPage);
456 });
457 }
458 hostNode->GetLayoutProperty()->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
459 }
460
FireNavDestinationStateChange(bool isShow)461 int32_t NavigationPattern::FireNavDestinationStateChange(bool isShow)
462 {
463 const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
464 auto errIndex = static_cast<int32_t>(navDestinationNodes.size());
465 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
466 CHECK_NULL_RETURN(hostNode, errIndex);
467 auto pipeline = PipelineContext::GetCurrentContext();
468 CHECK_NULL_RETURN(pipeline, errIndex);
469 int32_t standardIndex = hostNode->GetLastStandardIndex();
470 auto id = GetHost()->GetId();
471 for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1; index >= 0 && index >= standardIndex;
472 index--) {
473 const auto& curPath = navDestinationNodes[index];
474 auto curDestination =
475 AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavDestinationNode(curPath.second));
476 if (!curDestination) {
477 continue;
478 }
479 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
480 CHECK_NULL_RETURN(navDestinationPattern, errIndex);
481 if (navDestinationPattern->GetIsOnShow() == isShow) {
482 continue;
483 }
484 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
485 CHECK_NULL_RETURN(eventHub, errIndex);
486 if (isShow) {
487 NotifyPageShow(curPath.first);
488 auto param = Recorder::EventRecorder::Get().IsPageRecordEnable() ? navigationStack_->GetRouteParam() : "";
489 eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
490 navDestinationPattern->SetIsOnShow(true);
491 // The change from hiding to showing of top page means the navigation return to screen,
492 // so add window state callback again.
493 pipeline->AddWindowStateChangedCallback(id);
494 } else {
495 NotifyPageHide(curPath.first);
496 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
497 navDestinationPattern->SetIsOnShow(false);
498 // The change from showing to hiding of top page means the navigation leaves from screen,
499 // so remove window state callback.
500 pipeline->RemoveWindowStateChangedCallback(id);
501 }
502 }
503 return standardIndex;
504 }
505
FireNavigationStateChange(const RefPtr<UINode> & node,bool show)506 void NavigationPattern::FireNavigationStateChange(const RefPtr<UINode>& node, bool show)
507 {
508 CHECK_NULL_VOID(node);
509 const auto& children = node->GetChildren();
510 for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
511 auto& child = *iter;
512
513 auto navigation = AceType::DynamicCast<NavigationGroupNode>(child);
514 if (navigation) {
515 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigation->GetPattern());
516 CHECK_NULL_VOID(navigationPattern);
517 auto standardIndex = navigationPattern->FireNavDestinationStateChange(show);
518 const auto& navDestinationNodes = navigationPattern->navigationStack_->GetAllNavDestinationNodes();
519 if (standardIndex == static_cast<int32_t>(navDestinationNodes.size())) {
520 NavigationPattern::FireNavigationStateChange(child, show);
521 continue;
522 }
523 for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1;
524 index >= 0 && index >= standardIndex; index--) {
525 const auto& curPath = navDestinationNodes[index];
526 // Ignore node from navigation to navdestination in node tree, start from navdestination node directly.
527 NavigationPattern::FireNavigationStateChange(curPath.second, show);
528 }
529 } else {
530 NavigationPattern::FireNavigationStateChange(child, show);
531 }
532 }
533 }
534
NotifyPageHide(const std::string & pageName)535 void NavigationPattern::NotifyPageHide(const std::string& pageName)
536 {
537 auto container = Container::Current();
538 CHECK_NULL_VOID(container);
539 auto pageUrlChecker = container->GetPageUrlChecker();
540 CHECK_NULL_VOID(pageUrlChecker);
541 pageUrlChecker->NotifyPageHide(pageName);
542 }
543
NotifyPageShow(const std::string & pageName)544 void NavigationPattern::NotifyPageShow(const std::string& pageName)
545 {
546 auto container = Container::Current();
547 CHECK_NULL_VOID(container);
548 auto pageUrlChecker = container->GetPageUrlChecker();
549 CHECK_NULL_VOID(pageUrlChecker);
550 pageUrlChecker->NotifyPageShow(pageName);
551 }
552
TransitionWithOutAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage,bool needVisible)553 void NavigationPattern::TransitionWithOutAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
554 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage, bool needVisible)
555 {
556 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
557 CHECK_NULL_VOID(navigationNode);
558 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
559 CHECK_NULL_VOID(navBarNode);
560 auto pipeline = PipelineContext::GetCurrentContext();
561 CHECK_NULL_VOID(pipeline);
562
563 // replace
564 auto replaceVal = navigationStack_->GetReplaceValue();
565 if (replaceVal != 0) {
566 if (newTopNavDestination && preTopNavDestination) {
567 navigationNode->DealNavigationExit(preTopNavDestination, false, false);
568 } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
569 navigationNode->DealNavigationExit(navBarNode, true, false);
570 }
571 navigationNode->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
572 navigationStack_->UpdateReplaceValue(0);
573 return;
574 }
575
576 // navDestination push/pop navDestination
577 if (newTopNavDestination && preTopNavDestination) {
578 if (isPopPage) {
579 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
580 auto parent = preTopNavDestination->GetParent();
581 CHECK_NULL_VOID(parent);
582 if (preTopNavDestination->GetContentNode()) {
583 preTopNavDestination->GetContentNode()->Clean(false, true);
584 }
585 parent->RemoveChild(preTopNavDestination, true);
586 auto preTopNavDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
587 CHECK_NULL_VOID(preTopNavDestinationPattern);
588 preTopNavDestinationPattern->SetCustomNode(nullptr);
589 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
590 } else {
591 preTopNavDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
592 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
593 DealTransitionVisibility(preTopNavDestination, needVisible, false);
594 }
595 navigationNode->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
596 return;
597 }
598
599 // navBar push navDestination
600 if (newTopNavDestination && newTopNavDestination->GetNavDestinationMode() == NavDestinationMode::STANDARD &&
601 navigationMode_ == NavigationMode::STACK) {
602 auto navBar = AceType::DynamicCast<NavBarNode>(navBarNode);
603 if (navBar) {
604 navBar->SetTransitionType(PageTransitionType::EXIT_PUSH);
605 }
606 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
607 DealTransitionVisibility(navBarNode, false, true);
608 navigationNode->SetNeedSetInvisible(true);
609 }
610
611 // navDestination pop to navBar
612 if (preTopNavDestination) {
613 auto parent = preTopNavDestination->GetParent();
614 CHECK_NULL_VOID(parent);
615 if (preTopNavDestination->GetContentNode()) {
616 preTopNavDestination->GetContentNode()->Clean(false, true);
617 }
618 parent->RemoveChild(preTopNavDestination, true);
619 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
620 auto preTopNavDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
621 CHECK_NULL_VOID(preTopNavDestinationPattern);
622 preTopNavDestinationPattern->SetCustomNode(nullptr);
623 navigationNode->SetNeedSetInvisible(false);
624 auto navBar = AceType::DynamicCast<NavBarNode>(navBarNode);
625 if (navBar) {
626 navBar->SetTransitionType(PageTransitionType::ENTER_POP);
627 }
628 }
629 navigationNode->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
630 }
631
TransitionWithAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)632 void NavigationPattern::TransitionWithAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
633 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
634 {
635 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
636 CHECK_NULL_VOID(navigationNode);
637 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationNode->GetNavBarNode());
638 CHECK_NULL_VOID(navBarNode);
639 auto pipeline = PipelineContext::GetCurrentContext();
640 CHECK_NULL_VOID(pipeline);
641 auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
642 CHECK_NULL_VOID(layoutProperty);
643 if (layoutProperty->GetHideNavBarValue(false) && (!newTopNavDestination || !preTopNavDestination)) {
644 // hide navBarNode and need to do animation with navBarNode
645 if (preTopNavDestination) {
646 // remove preTopNavDestination node in pop
647 auto parent = preTopNavDestination->GetParent();
648 CHECK_NULL_VOID(parent);
649 if (preTopNavDestination->GetContentNode()) {
650 preTopNavDestination->GetContentNode()->Clean();
651 }
652 parent->RemoveChild(preTopNavDestination);
653 auto preTopNavDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
654 CHECK_NULL_VOID(preTopNavDestinationPattern);
655 preTopNavDestinationPattern->SetCustomNode(nullptr);
656 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
657 }
658 return;
659 }
660 if (isCustomAnimation_ && TriggerCustomAnimation(preTopNavDestination, newTopNavDestination, isPopPage)) {
661 return;
662 }
663
664 // replace
665 auto replaceValue = navigationStack_->GetReplaceValue();
666 if (replaceValue != 0) {
667 if (newTopNavDestination && preTopNavDestination) {
668 navigationNode->TransitionWithReplace(preTopNavDestination, newTopNavDestination, false);
669 } else if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
670 navigationNode->TransitionWithReplace(navBarNode, newTopNavDestination, true);
671 }
672 navigationStack_->UpdateReplaceValue(0);
673 return;
674 }
675
676 // navDestination push/pop navDestination
677 if (newTopNavDestination && preTopNavDestination) {
678 if (isPopPage) {
679 navigationNode->TransitionWithPop(preTopNavDestination, newTopNavDestination);
680 } else {
681 navigationNode->TransitionWithPush(preTopNavDestination, newTopNavDestination);
682 }
683 return;
684 }
685
686 // navBar push navDestination
687 if (newTopNavDestination && navigationMode_ == NavigationMode::STACK) {
688 navigationNode->TransitionWithPush(navBarNode, newTopNavDestination, true);
689 return;
690 }
691
692 // navDestination pop to navBar
693 if (preTopNavDestination) {
694 if (navigationMode_ == NavigationMode::SPLIT) {
695 navigationNode->TransitionWithPop(preTopNavDestination, nullptr);
696 }
697 if (navigationMode_ == NavigationMode::STACK) {
698 navigationNode->TransitionWithPop(preTopNavDestination, navBarNode, true);
699 }
700 }
701 }
702
OnVisibleChange(bool isVisible)703 void NavigationPattern::OnVisibleChange(bool isVisible)
704 {
705 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
706 CHECK_NULL_VOID(hostNode);
707 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
708 CHECK_NULL_VOID(eventHub);
709 eventHub->FireNavBarStateChangeEvent(isVisible);
710 }
711
OnNavBarStateChange(bool modeChange)712 void NavigationPattern::OnNavBarStateChange(bool modeChange)
713 {
714 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
715 CHECK_NULL_VOID(layoutProperty);
716 auto visibilityValue = layoutProperty->GetVisibilityValue(VisibleType::VISIBLE);
717 if (visibilityValue != VisibleType::VISIBLE) {
718 return;
719 }
720
721 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
722 CHECK_NULL_VOID(hostNode);
723 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
724 CHECK_NULL_VOID(eventHub);
725 auto currentNavigationMode = GetNavigationMode();
726
727 if (modeChange) {
728 if (currentNavigationMode == NavigationMode::SPLIT) {
729 if (layoutProperty->GetHideNavBarValue(false)) {
730 eventHub->FireNavBarStateChangeEvent(false);
731 } else {
732 eventHub->FireNavBarStateChangeEvent(true);
733 }
734 } else {
735 if (navigationStack_->Empty() && !layoutProperty->GetHideNavBarValue(false)) {
736 eventHub->FireNavBarStateChangeEvent(true);
737 } else {
738 eventHub->FireNavBarStateChangeEvent(false);
739 }
740 }
741 SetNavBarVisibilityChange(false);
742 return;
743 }
744
745 if (GetNavBarVisibilityChange()) {
746 if (!layoutProperty->GetHideNavBarValue(false)) {
747 eventHub->FireNavBarStateChangeEvent(true);
748 } else {
749 eventHub->FireNavBarStateChangeEvent(false);
750 }
751 SetNavBarVisibilityChange(false);
752 return;
753 }
754
755 // STACK mode, check navigationStack
756 if (navigationStack_->Empty()) {
757 eventHub->FireNavBarStateChangeEvent(true);
758 } else {
759 eventHub->FireNavBarStateChangeEvent(false);
760 }
761 }
762
OnNavigationModeChange(bool modeChange)763 void NavigationPattern::OnNavigationModeChange(bool modeChange)
764 {
765 if (!modeChange) {
766 return;
767 }
768 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
769 CHECK_NULL_VOID(hostNode);
770 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
771 CHECK_NULL_VOID(eventHub);
772 eventHub->FireNavigationModeChangeEvent(navigationMode_);
773 }
774
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)775 bool NavigationPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
776 {
777 if (config.skipMeasure && config.skipLayout) {
778 return false;
779 }
780 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
781 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
782 auto navigationLayoutAlgorithm =
783 DynamicCast<NavigationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
784 CHECK_NULL_RETURN(navigationLayoutAlgorithm, false);
785 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
786 CHECK_NULL_RETURN(hostNode, false);
787 auto context = PipelineContext::GetCurrentContext();
788 if (context) {
789 context->GetTaskExecutor()->PostTask(
790 [weak = WeakClaim(this), navigationStackWeak = WeakPtr<NavigationStack>(navigationStack_),
791 navigationWeak = WeakPtr<NavigationGroupNode>(hostNode)] {
792 auto pattern = weak.Upgrade();
793 CHECK_NULL_VOID(pattern);
794 auto navigationGroupNode = navigationWeak.Upgrade();
795 CHECK_NULL_VOID(navigationGroupNode);
796 auto navigationLayoutProperty =
797 AceType::DynamicCast<NavigationLayoutProperty>(navigationGroupNode->GetLayoutProperty());
798 CHECK_NULL_VOID(navigationLayoutProperty);
799 auto navigationStack = navigationStackWeak.Upgrade();
800 CHECK_NULL_VOID(navigationStack);
801 auto navigationContentNode = AceType::DynamicCast<FrameNode>(navigationGroupNode->GetContentNode());
802 CHECK_NULL_VOID(navigationContentNode);
803 auto navDestinationNode =
804 AceType::DynamicCast<NavDestinationGroupNode>(navigationContentNode->GetLastChild());
805 CHECK_NULL_VOID(navDestinationNode);
806 auto navDestinationPattern = navDestinationNode->GetPattern<NavDestinationPattern>();
807 auto curTopNavPath = navigationStack->GetTopNavPath();
808 if (curTopNavPath.has_value()) {
809 // considering backButton visibility
810 auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
811 NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
812 pattern->UpdateContextRect(curTopNavDestination, navigationGroupNode);
813 if (pattern->isChanged_ && curTopNavDestination) {
814 pattern->NotifyDialogChange(true, true);
815 pattern->isChanged_ = false;
816 }
817 }
818 // considering navBar visibility
819 auto navBarNode = AceType::DynamicCast<NavBarNode>(navigationGroupNode->GetNavBarNode());
820 CHECK_NULL_VOID(navBarNode);
821 auto navBarLayoutProperty = navBarNode->GetLayoutProperty<NavBarLayoutProperty>();
822 CHECK_NULL_VOID(navBarLayoutProperty);
823 bool isSetInvisible =
824 (navigationGroupNode->GetNeedSetInvisible() && navigationStack->Size() != 0) ? true : false;
825 if (navigationLayoutProperty->GetHideNavBar().value_or(false) ||
826 (pattern->GetNavigationMode() == NavigationMode::STACK && isSetInvisible)) {
827 navBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
828 navBarNode->SetJSViewActive(false);
829 } else {
830 navBarNode->GetRenderContext()->UpdateOpacity(1.0f);
831 navBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
832 navBarNode->SetJSViewActive(true);
833 }
834 if (navDestinationNode->GetChildren().size() <= EMPTY_DESTINATION_CHILD_SIZE &&
835 navDestinationPattern->GetBackButtonState()) {
836 auto focusHub = navDestinationNode->GetOrCreateFocusHub();
837 focusHub->SetFocusable(true);
838 focusHub->SetParentFocusable(true);
839 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationNode->GetTitleBarNode());
840 CHECK_NULL_VOID(titleBarNode);
841 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
842 backButtonNode->GetOrCreateFocusHub()->SetIsDefaultFocus(true);
843 focusHub->RequestFocusWithDefaultFocusFirstly();
844 }
845 },
846 TaskExecutor::TaskType::UI);
847 }
848 auto navigationLayoutProperty = AceType::DynamicCast<NavigationLayoutProperty>(hostNode->GetLayoutProperty());
849 CHECK_NULL_RETURN(navigationLayoutProperty, false);
850 UpdateTitleModeChangeEventHub(hostNode);
851 AddDividerHotZoneRect();
852 ifNeedInit_ = false;
853 return false;
854 }
855
UpdateContextRect(const RefPtr<NavDestinationGroupNode> & curDestination,const RefPtr<NavigationGroupNode> & hostNode)856 void NavigationPattern::UpdateContextRect(
857 const RefPtr<NavDestinationGroupNode>& curDestination, const RefPtr<NavigationGroupNode>& hostNode)
858 {
859 CHECK_NULL_VOID(curDestination);
860 CHECK_NULL_VOID(hostNode);
861 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
862 CHECK_NULL_VOID(navBarNode);
863 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(hostNode->GetPattern());
864 CHECK_NULL_VOID(navigationPattern);
865
866 if (navigationPattern->GetNavigationMode() == NavigationMode::STACK) {
867 curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
868 return;
869 }
870 auto navigationLayoutProperty = hostNode->GetLayoutProperty<NavigationLayoutProperty>();
871 CHECK_NULL_VOID(navigationLayoutProperty);
872 auto navBarProperty = navBarNode->GetLayoutProperty();
873 navBarProperty->UpdateVisibility(VisibleType::VISIBLE);
874 navBarNode->SetJSViewActive(true);
875 if (!curDestination->IsOnAnimation()) {
876 curDestination->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
877 curDestination->GetRenderContext()->SetActualForegroundColor(Color::TRANSPARENT);
878 navBarNode->GetEventHub<EventHub>()->SetEnabledInternal(true);
879 auto titleBarNode = DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
880 CHECK_NULL_VOID(titleBarNode);
881 auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
882 CHECK_NULL_VOID(titleNode);
883 titleNode->GetRenderContext()->UpdateTranslateInXY(OffsetF { 0.0f, 0.0f });
884 }
885 }
886
UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode> & hostNode)887 bool NavigationPattern::UpdateTitleModeChangeEventHub(const RefPtr<NavigationGroupNode>& hostNode)
888 {
889 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
890 CHECK_NULL_RETURN(navBarNode, false);
891 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navBarNode->GetTitleBarNode());
892 CHECK_NULL_RETURN(titleBarNode, false);
893 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
894 CHECK_NULL_RETURN(titleBarLayoutProperty, false);
895 auto eventHub = hostNode->GetEventHub<NavigationEventHub>();
896 CHECK_NULL_RETURN(eventHub, false);
897 if (titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::FREE) == NavigationTitleMode::FREE) {
898 auto titleBarPattern = AceType::DynamicCast<TitleBarPattern>(titleBarNode->GetPattern());
899 CHECK_NULL_RETURN(titleBarPattern, false);
900 NavigationTitleMode titleMode = titleBarPattern->GetNavigationTitleMode();
901 if (titleMode != NavigationTitleMode::FREE && titleMode_ != titleMode) {
902 NavigationTitleModeChangeEvent navigationTitleModeChange(titleMode == NavigationTitleMode::MINI);
903 eventHub->FireChangeEvent(&navigationTitleModeChange);
904 titleMode_ = titleMode;
905 }
906 }
907 return true;
908 }
909
GenerateUINodeByIndex(int32_t index)910 RefPtr<UINode> NavigationPattern::GenerateUINodeByIndex(int32_t index)
911 {
912 return navigationStack_->CreateNodeByIndex(index);
913 }
914
InitDividerMouseEvent(const RefPtr<InputEventHub> & inputHub)915 void NavigationPattern::InitDividerMouseEvent(const RefPtr<InputEventHub>& inputHub)
916 {
917 CHECK_NULL_VOID(inputHub);
918 CHECK_NULL_VOID(!hoverEvent_);
919
920 auto hoverTask = [weak = WeakClaim(this)](bool isHover) {
921 auto pattern = weak.Upgrade();
922 if (pattern) {
923 pattern->OnHover(isHover);
924 }
925 };
926 hoverEvent_ = MakeRefPtr<InputEvent>(std::move(hoverTask));
927 inputHub->AddOnHoverEvent(hoverEvent_);
928 }
929
HandleDragStart()930 void NavigationPattern::HandleDragStart()
931 {
932 preNavBarWidth_ = realNavBarWidth_;
933 if (!isDividerDraggable_) {
934 return;
935 }
936 isInDividerDrag_ = true;
937 auto pipeline = PipelineContext::GetCurrentContext();
938 CHECK_NULL_VOID(pipeline);
939 auto windowId = pipeline->GetWindowId();
940 auto mouseStyle = MouseStyle::CreateMouseStyle();
941 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), MouseFormat::RESIZE_LEFT_RIGHT);
942 }
943
HandleDragUpdate(float xOffset)944 void NavigationPattern::HandleDragUpdate(float xOffset)
945 {
946 auto navigationLayoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
947 CHECK_NULL_VOID(navigationLayoutProperty);
948 auto host = GetHost();
949 CHECK_NULL_VOID(host);
950 auto geometryNode = host->GetGeometryNode();
951 CHECK_NULL_VOID(geometryNode);
952 auto frameSize = geometryNode->GetFrameSize();
953 auto frameWidth = frameSize.Width();
954 auto constraint = navigationLayoutProperty->GetLayoutConstraint();
955 auto parentSize = CreateIdealSize(constraint.value(), Axis::HORIZONTAL, MeasureType::MATCH_PARENT);
956
957 float minNavBarWidthPx = minNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
958 float maxNavBarWidthPx = maxNavBarWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
959 float minContentWidthPx = minContentWidthValue_.ConvertToPxWithSize(parentSize.Width().value_or(0.0f));
960 auto dividerWidth = static_cast<float>(DIVIDER_WIDTH.ConvertToPx());
961
962 auto navigationPosition = navigationLayoutProperty->GetNavBarPosition().value_or(NavBarPosition::START);
963 bool isNavBarStart = navigationPosition == NavBarPosition::START;
964 auto navBarLine = preNavBarWidth_ + (isNavBarStart ? xOffset : -xOffset);
965 float currentNavBarWidth = realNavBarWidth_;
966
967 if (maxNavBarWidthPx + dividerWidth + minContentWidthPx > frameWidth) {
968 maxNavBarWidthPx = frameWidth - minContentWidthPx - dividerWidth;
969 }
970 navBarLine = std::min(navBarLine, maxNavBarWidthPx);
971
972 if (userSetMinContentFlag_ && !userSetNavBarRangeFlag_) {
973 if (minContentWidthPx >= frameWidth) {
974 realNavBarWidth_ = 0.0f;
975 } else if (navBarLine + dividerWidth + minContentWidthPx <= frameWidth) {
976 realNavBarWidth_ = navBarLine;
977 } else {
978 realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
979 }
980 } else {
981 realDividerWidth_ = dividerWidth;
982 float remainingSpace = frameWidth - navBarLine - dividerWidth;
983 if (remainingSpace >= minContentWidthPx) {
984 realNavBarWidth_ = navBarLine;
985 } else if (remainingSpace < minContentWidthPx && navBarLine > minNavBarWidthPx) {
986 realNavBarWidth_ = frameWidth - minContentWidthPx - dividerWidth;
987 } else {
988 realNavBarWidth_ = minNavBarWidthPx;
989 }
990 }
991 realNavBarWidth_ = std::min(realNavBarWidth_, frameWidth);
992 realNavBarWidth_ = std::min(realNavBarWidth_, maxNavBarWidthPx);
993 realNavBarWidth_ = std::max(realNavBarWidth_, minNavBarWidthPx);
994
995 // MEASURE
996 if (realNavBarWidth_ != currentNavBarWidth) {
997 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
998 }
999 }
1000
HandleDragEnd()1001 void NavigationPattern::HandleDragEnd()
1002 {
1003 preNavBarWidth_ = realNavBarWidth_;
1004 if (!isDividerDraggable_) {
1005 return;
1006 }
1007 isInDividerDrag_ = false;
1008 auto pipeline = PipelineContext::GetCurrentContext();
1009 CHECK_NULL_VOID(pipeline);
1010 auto windowId = pipeline->GetWindowId();
1011 auto mouseStyle = MouseStyle::CreateMouseStyle();
1012 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), MouseFormat::DEFAULT);
1013 }
1014
InitDragEvent(const RefPtr<GestureEventHub> & gestureHub)1015 void NavigationPattern::InitDragEvent(const RefPtr<GestureEventHub>& gestureHub)
1016 {
1017 CHECK_NULL_VOID(!dragEvent_);
1018 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1019 auto pattern = weak.Upgrade();
1020 CHECK_NULL_VOID(pattern);
1021 pattern->HandleDragStart();
1022 };
1023 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1024 auto pattern = weak.Upgrade();
1025 CHECK_NULL_VOID(pattern);
1026 pattern->HandleDragUpdate(static_cast<float>(info.GetOffsetX()));
1027 };
1028 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
1029 auto pattern = weak.Upgrade();
1030 CHECK_NULL_VOID(pattern);
1031 pattern->HandleDragEnd();
1032 };
1033 auto actionCancelTask = [weak = WeakClaim(this)]() {
1034 auto pattern = weak.Upgrade();
1035 CHECK_NULL_VOID(pattern);
1036 pattern->HandleDragEnd();
1037 };
1038 dragEvent_ = MakeRefPtr<DragEvent>(
1039 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
1040 PanDirection panDirection = { .type = PanDirection::HORIZONTAL };
1041 gestureHub->SetDragEvent(dragEvent_, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
1042 }
1043
OnHover(bool isHover)1044 void NavigationPattern::OnHover(bool isHover)
1045 {
1046 if (isInDividerDrag_) {
1047 return;
1048 }
1049 MouseFormat format = isHover ? MouseFormat::RESIZE_LEFT_RIGHT : MouseFormat::DEFAULT;
1050 auto pipeline = PipelineContext::GetCurrentContext();
1051 CHECK_NULL_VOID(pipeline);
1052 auto windowId = pipeline->GetWindowId();
1053 auto mouseStyle = MouseStyle::CreateMouseStyle();
1054 int32_t currentPointerStyle = 0;
1055 mouseStyle->GetPointerStyle(static_cast<int32_t>(windowId), currentPointerStyle);
1056 auto layoutProperty = GetLayoutProperty<NavigationLayoutProperty>();
1057 CHECK_NULL_VOID(layoutProperty);
1058 auto userSetMinNavBarWidthValue = layoutProperty->GetMinNavBarWidthValue(Dimension(0.0));
1059 auto userSetMaxNavBarWidthValue = layoutProperty->GetMaxNavBarWidthValue(Dimension(0.0));
1060 bool navBarWidthRangeEqual = userSetMinNavBarWidthValue.Value() >= userSetMaxNavBarWidthValue.Value();
1061 if ((userSetNavBarWidthFlag_ && !userSetNavBarRangeFlag_) || (userSetNavBarRangeFlag_ && navBarWidthRangeEqual)) {
1062 isDividerDraggable_ = false;
1063 return;
1064 }
1065 isDividerDraggable_ = true;
1066 if (currentPointerStyle != static_cast<int32_t>(format)) {
1067 mouseStyle->SetPointerStyle(static_cast<int32_t>(windowId), format);
1068 }
1069 }
1070
GetDividerNode() const1071 RefPtr<FrameNode> NavigationPattern::GetDividerNode() const
1072 {
1073 auto host = GetHost();
1074 CHECK_NULL_RETURN(host, nullptr);
1075 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(host);
1076 CHECK_NULL_RETURN(navigationNode, nullptr);
1077 auto dividerFrameNode = AceType::DynamicCast<FrameNode>(navigationNode->GetDividerNode());
1078 CHECK_NULL_RETURN(dividerFrameNode, nullptr);
1079 return dividerFrameNode;
1080 }
1081
AddDividerHotZoneRect()1082 void NavigationPattern::AddDividerHotZoneRect()
1083 {
1084 if (realDividerWidth_ <= 0.0f) {
1085 return;
1086 }
1087 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1088 CHECK_NULL_VOID(hostNode);
1089 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
1090 CHECK_NULL_VOID(navBarNode);
1091 auto geometryNode = navBarNode->GetGeometryNode();
1092 CHECK_NULL_VOID(geometryNode);
1093
1094 OffsetF hotZoneOffset;
1095 hotZoneOffset.SetX(-DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
1096 hotZoneOffset.SetY(DEFAULT_DIVIDER_START_MARGIN.ConvertToPx());
1097 SizeF hotZoneSize;
1098 hotZoneSize.SetWidth(realDividerWidth_ + DIVIDER_HOT_ZONE_HORIZONTAL_PADDING_NUM *
1099 DEFAULT_DIVIDER_HOT_ZONE_HORIZONTAL_PADDING.ConvertToPx());
1100 hotZoneSize.SetHeight(geometryNode->GetFrameSize().Height());
1101 DimensionRect hotZoneRegion;
1102 if (navigationMode_ == NavigationMode::STACK) {
1103 hotZoneRegion.SetSize(DimensionSize(Dimension(0.0f), Dimension(0.0f)));
1104 } else {
1105 hotZoneRegion.SetSize(DimensionSize(Dimension(hotZoneSize.Width()), Dimension(hotZoneSize.Height())));
1106 }
1107 hotZoneRegion.SetOffset(DimensionOffset(Dimension(hotZoneOffset.GetX()), Dimension(hotZoneOffset.GetY())));
1108
1109 std::vector<DimensionRect> mouseRegion;
1110 mouseRegion.emplace_back(hotZoneRegion);
1111
1112 auto dividerFrameNode = GetDividerNode();
1113 CHECK_NULL_VOID(dividerFrameNode);
1114 auto dividerGestureHub = dividerFrameNode->GetOrCreateGestureEventHub();
1115 CHECK_NULL_VOID(dividerGestureHub);
1116 dividerGestureHub->SetMouseResponseRegion(mouseRegion);
1117
1118 auto dragRectOffset = geometryNode->GetMarginFrameOffset();
1119 dragRectOffset.SetX(-DEFAULT_DRAG_REGION.ConvertToPx());
1120 dragRect_.SetOffset(dragRectOffset);
1121 if (navigationMode_ == NavigationMode::STACK) {
1122 dragRect_.SetSize(SizeF(0.0f, 0.0f));
1123 } else {
1124 dragRect_.SetSize(SizeF(DEFAULT_DRAG_REGION.ConvertToPx() * DEFAULT_HALF + realDividerWidth_,
1125 geometryNode->GetFrameSize().Height()));
1126 }
1127
1128 std::vector<DimensionRect> responseRegion;
1129 DimensionOffset responseOffset(dragRectOffset);
1130 DimensionRect responseRect(Dimension(dragRect_.Width(), DimensionUnit::PX),
1131 Dimension(dragRect_.Height(), DimensionUnit::PX), responseOffset);
1132 responseRegion.emplace_back(responseRect);
1133 dividerGestureHub->SetResponseRegion(responseRegion);
1134 }
1135
OnWindowHide()1136 void NavigationPattern::OnWindowHide()
1137 {
1138 auto curTopNavPath = navigationStack_->GetTopNavPath();
1139 CHECK_NULL_VOID(curTopNavPath.has_value());
1140 CHECK_NULL_VOID(curTopNavPath->second);
1141 auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1142 NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
1143 CHECK_NULL_VOID(curTopNavDestination);
1144 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(curTopNavDestination->GetPattern());
1145 CHECK_NULL_VOID(navDestinationPattern);
1146 CHECK_NULL_VOID(navDestinationPattern->GetIsOnShow());
1147 auto eventHub = curTopNavDestination->GetEventHub<NavDestinationEventHub>();
1148 CHECK_NULL_VOID(eventHub);
1149 NotifyPageHide(curTopNavPath->first);
1150 NotifyDialogChange(false, true);
1151 }
1152
OnWindowShow()1153 void NavigationPattern::OnWindowShow()
1154 {
1155 auto curTopNavPath = navigationStack_->GetTopNavPath();
1156 CHECK_NULL_VOID(curTopNavPath.has_value());
1157 CHECK_NULL_VOID(curTopNavPath->second);
1158 auto curTopNavDestination = AceType::DynamicCast<NavDestinationGroupNode>(
1159 NavigationGroupNode::GetNavDestinationNode(curTopNavPath->second));
1160 CHECK_NULL_VOID(curTopNavDestination);
1161 auto navDestinationPattern = AceType::DynamicCast<NavDestinationPattern>(curTopNavDestination->GetPattern());
1162 CHECK_NULL_VOID(navDestinationPattern);
1163 CHECK_NULL_VOID(!(navDestinationPattern->GetIsOnShow()));
1164 auto eventHub = curTopNavDestination->GetEventHub<NavDestinationEventHub>();
1165 NotifyPageShow(curTopNavPath->first);
1166 NotifyDialogChange(true, true);
1167 }
1168
NotifyDialogChange(bool isShow,bool isNavigationChanged)1169 void NavigationPattern::NotifyDialogChange(bool isShow, bool isNavigationChanged)
1170 {
1171 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1172 const auto& navDestinationNodes = navigationStack_->GetAllNavDestinationNodes();
1173 int32_t standardIndex = hostNode->GetLastStandardIndex();
1174 if (isShow) {
1175 int32_t startIndex = standardIndex > 0 ? standardIndex : 0;
1176 for (int32_t index = startIndex; index < static_cast<int32_t>(navDestinationNodes.size()); index++) {
1177 const auto& curPath = navDestinationNodes[index];
1178 auto curDestination =
1179 AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavDestinationNode(curPath.second));
1180 if (!curDestination) {
1181 continue;
1182 }
1183 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1184 if (navDestinationPattern->GetIsOnShow()) {
1185 continue;
1186 }
1187 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
1188 if (isNavigationChanged) {
1189 NavigationPattern::FireNavigationStateChange(curDestination, true);
1190 }
1191 auto param = Recorder::EventRecorder::Get().IsPageRecordEnable() ? navigationStack_->GetRouteParam() : "";
1192 eventHub->FireOnShownEvent(navDestinationPattern->GetName(), param);
1193 navDestinationPattern->SetIsOnShow(true);
1194 }
1195 } else {
1196 for (int32_t index = static_cast<int32_t>(navDestinationNodes.size()) - 1;
1197 index >= 0 && index >= standardIndex; index--) {
1198 const auto& curPath = navDestinationNodes[index];
1199 auto curDestination =
1200 AceType::DynamicCast<NavDestinationGroupNode>(hostNode->GetNavDestinationNode(curPath.second));
1201 if (!curDestination) {
1202 continue;
1203 }
1204 auto navDestinationPattern = curDestination->GetPattern<NavDestinationPattern>();
1205 if (!navDestinationPattern->GetIsOnShow()) {
1206 continue;
1207 }
1208 auto eventHub = curDestination->GetEventHub<NavDestinationEventHub>();
1209 if (isNavigationChanged) {
1210 NavigationPattern::FireNavigationStateChange(curDestination, false);
1211 }
1212 eventHub->FireOnHiddenEvent(navDestinationPattern->GetName());
1213 navDestinationPattern->SetIsOnShow(false);
1214 }
1215 }
1216 }
1217
DumpInfo()1218 void NavigationPattern::DumpInfo()
1219 {
1220 if (!navigationStack_) {
1221 return;
1222 }
1223 DumpLog::GetInstance().AddDesc(std::string("size").append(std::to_string(navigationStack_->Size())));
1224 }
1225
TriggerCustomAnimation(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)1226 bool NavigationPattern::TriggerCustomAnimation(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1227 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
1228 {
1229 if ((!preTopNavDestination && !newTopNavDestination) || !onTransition_) {
1230 return false;
1231 }
1232 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1233 hostNode->SetIsOnAnimation(true);
1234 if (!newTopNavDestination) {
1235 // pop animation with top navDestination, recover navBar visible tag
1236 hostNode->SetNeedSetInvisible(false);
1237 }
1238 PerfMonitor::GetPerfMonitor()->Start(PerfConstants::ABILITY_OR_PAGE_SWITCH, PerfActionType::LAST_UP, "");
1239 auto proxy = AceType::MakeRefPtr<NavigationTransitionProxy>();
1240 proxy->SetPreDestination(preTopNavDestination);
1241 proxy->SetTopDestination(newTopNavDestination);
1242 proxy->SetIsSuccess(true);
1243 currentProxy_ = proxy;
1244 auto navigationTransition = ExecuteTransition(preTopNavDestination, newTopNavDestination, isPopPage);
1245 if (!navigationTransition.isValid) {
1246 return false;
1247 }
1248 auto transition = navigationTransition.transition;
1249 proxy->SetFinishTransitionEvent([weakPattern = WeakClaim(this), preTopNavDestination, newTopNavDestination, proxy,
1250 isPopPage, endCallBack = navigationTransition.endCallback](bool isSuccess) {
1251 auto navigationPattern = weakPattern.Upgrade();
1252 CHECK_NULL_VOID(navigationPattern);
1253 if (proxy != nullptr && proxy->GetIsFinished()) {
1254 TAG_LOGD(AceLogTag::ACE_NAVIGATION, "custom animation has finished");
1255 return;
1256 }
1257 if (endCallBack) {
1258 // current transition end doesn't has failed
1259 endCallBack(isSuccess);
1260 }
1261 navigationPattern->OnCustomAnimationFinish(preTopNavDestination, newTopNavDestination, isPopPage);
1262 if (proxy != nullptr) {
1263 proxy->SetIsFinished(true);
1264 }
1265 });
1266 transition(proxy);
1267 auto timeout = navigationTransition.timeout;
1268 // post timeout task
1269 auto pipeline = PipelineContext::GetCurrentContext();
1270 CHECK_NULL_RETURN(pipeline, true);
1271 auto taskExecutor = pipeline->GetTaskExecutor();
1272 CHECK_NULL_RETURN(taskExecutor, true);
1273 taskExecutor->PostDelayedTask(
1274 [weakProxy = WeakPtr<NavigationTransitionProxy>(proxy)] {
1275 auto transitionProxy = weakProxy.Upgrade();
1276 CHECK_NULL_VOID(transitionProxy);
1277 transitionProxy->FireFinishCallback();
1278 },
1279 TaskExecutor::TaskType::UI, timeout);
1280 RefPtr<EventHub> eventHub;
1281 if (!preTopNavDestination && navigationMode_ == NavigationMode::STACK) {
1282 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1283 CHECK_NULL_RETURN(hostNode, true);
1284 auto navBarNode = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
1285 CHECK_NULL_RETURN(navBarNode, true);
1286 eventHub = navBarNode->GetEventHub<EventHub>();
1287 }
1288 if (preTopNavDestination) {
1289 eventHub = preTopNavDestination->GetEventHub<EventHub>();
1290 }
1291 CHECK_NULL_RETURN(eventHub, true);
1292 eventHub->SetEnabledInternal(false);
1293 return true;
1294 }
1295
OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode> & preTopNavDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)1296 void NavigationPattern::OnCustomAnimationFinish(const RefPtr<NavDestinationGroupNode>& preTopNavDestination,
1297 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
1298 {
1299 if (!preTopNavDestination && !newTopNavDestination) {
1300 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "preDestination and topDestination is invalid");
1301 return;
1302 }
1303 PerfMonitor::GetPerfMonitor()->End(PerfConstants::ABILITY_OR_PAGE_SWITCH, true);
1304 auto replaceValue = navigationStack_->GetReplaceValue();
1305 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1306 CHECK_NULL_VOID(hostNode);
1307 hostNode->SetIsOnAnimation(false);
1308 hostNode->OnAccessibilityEvent(AccessibilityEventType::PAGE_CHANGE);
1309 do {
1310 if (replaceValue != 0) {
1311 hostNode->DealNavigationExit(preTopNavDestination, preTopNavDestination == nullptr);
1312 navigationStack_->UpdateReplaceValue(0);
1313 break;
1314 }
1315 if ((newTopNavDestination && preTopNavDestination && isPopPage) ||
1316 (preTopNavDestination && !newTopNavDestination)) {
1317 PageTransitionType preNodeTransitionType = preTopNavDestination->GetTransitionType();
1318 if (preNodeTransitionType != PageTransitionType::EXIT_POP) {
1319 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
1320 return;
1321 }
1322 auto preDestinationPattern = preTopNavDestination->GetPattern<NavDestinationPattern>();
1323 CHECK_NULL_VOID(preDestinationPattern);
1324 auto shallowBuilder = preDestinationPattern->GetShallowBuilder();
1325 if (shallowBuilder) {
1326 shallowBuilder->MarkIsExecuteDeepRenderDone(false);
1327 }
1328 auto parent = preTopNavDestination->GetParent();
1329 CHECK_NULL_VOID(parent);
1330 parent->RemoveChild(preTopNavDestination);
1331 preDestinationPattern->SetCustomNode(nullptr);
1332 parent->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1333 break;
1334 }
1335 if ((newTopNavDestination && preTopNavDestination && !isPopPage) ||
1336 (!preTopNavDestination && newTopNavDestination && navigationMode_ == NavigationMode::STACK)) {
1337 hostNode->SetNeedSetInvisible(true);
1338 RefPtr<FrameNode> node;
1339 PageTransitionType preNodeTransitionType;
1340 if (preTopNavDestination) {
1341 preNodeTransitionType = preTopNavDestination->GetTransitionType();
1342 node = preTopNavDestination;
1343 } else {
1344 // pre destination is nullptr, preNode is navBarNode
1345 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
1346 CHECK_NULL_VOID(navBarNode);
1347 preNodeTransitionType = navBarNode->GetTransitionType();
1348 node = AceType::DynamicCast<FrameNode>(hostNode->GetNavBarNode());
1349 CHECK_NULL_VOID(node);
1350 }
1351 if (preNodeTransitionType != PageTransitionType::EXIT_PUSH) {
1352 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "previous destination node is executing another transition");
1353 return;
1354 }
1355 auto property = node->GetLayoutProperty();
1356 property->UpdateVisibility(VisibleType::INVISIBLE);
1357 node->SetJSViewActive(false);
1358 if (!preTopNavDestination) {
1359 hostNode->NotifyPageHide();
1360 }
1361 // recover event hub
1362 auto eventHub = node->GetEventHub<EventHub>();
1363 if (eventHub) {
1364 eventHub->SetEnabledInternal(true);
1365 }
1366 }
1367 } while (0);
1368 auto context = PipelineContext::GetCurrentContext();
1369 CHECK_NULL_VOID(context);
1370 context->MarkNeedFlushMouseEvent();
1371 }
1372
ExecuteTransition(const RefPtr<NavDestinationGroupNode> & preTopDestination,const RefPtr<NavDestinationGroupNode> & newTopNavDestination,bool isPopPage)1373 NavigationTransition NavigationPattern::ExecuteTransition(const RefPtr<NavDestinationGroupNode>& preTopDestination,
1374 const RefPtr<NavDestinationGroupNode>& newTopNavDestination, bool isPopPage)
1375 {
1376 NavigationTransition navigationTransition;
1377 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1378 CHECK_NULL_RETURN(hostNode, navigationTransition);
1379 NavigationOperation operation;
1380 NavContentInfo preInfo = currentProxy_->GetPreDestination();
1381 NavContentInfo topInfo = currentProxy_->GetTopDestination();
1382 auto replaceValue = navigationStack_->GetReplaceValue();
1383 if (replaceValue != 0) {
1384 operation = NavigationOperation::REPLACE;
1385 // recover replace tag
1386 navigationStack_->UpdateReplaceValue(0);
1387 } else if (!preTopDestination) {
1388 preInfo.index = -1;
1389 operation = NavigationOperation::PUSH;
1390 // if animated with navBarNode, recover navBar visibility
1391 hostNode->SetNeedSetInvisible(false);
1392 } else if (!newTopNavDestination) {
1393 operation = NavigationOperation::POP;
1394 } else if (isPopPage) {
1395 operation = NavigationOperation::POP;
1396 } else {
1397 operation = NavigationOperation::PUSH;
1398 }
1399
1400 /* set transition animation flag fro navBarNode or navDestinationNode */
1401 if (operation == NavigationOperation::PUSH) {
1402 if (preTopDestination != nullptr) {
1403 preTopDestination->SetTransitionType(PageTransitionType::EXIT_PUSH);
1404 } else {
1405 // preTopDestination is nullptr, previous node is navBar node
1406 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
1407 CHECK_NULL_RETURN(navBarNode, navigationTransition);
1408 navBarNode->SetTransitionType(PageTransitionType::EXIT_PUSH);
1409 }
1410
1411 if (newTopNavDestination != nullptr) {
1412 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_PUSH);
1413 }
1414 }
1415 if (operation == NavigationOperation::POP) {
1416 if (preTopDestination != nullptr) {
1417 preTopDestination->SetTransitionType(PageTransitionType::EXIT_POP);
1418 }
1419 if (newTopNavDestination != nullptr) {
1420 newTopNavDestination->SetTransitionType(PageTransitionType::ENTER_POP);
1421 } else {
1422 // newTopNavDestination is nullptr, current node is navBar node
1423 auto navBarNode = AceType::DynamicCast<NavBarNode>(hostNode->GetNavBarNode());
1424 CHECK_NULL_RETURN(navBarNode, navigationTransition);
1425 navBarNode->SetTransitionType(PageTransitionType::ENTER_POP);
1426 }
1427 }
1428 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "custom animation start: operation: %{public}d", operation);
1429 return onTransition_(preInfo, topInfo, operation);
1430 }
1431
OnColorConfigurationUpdate()1432 void NavigationPattern::OnColorConfigurationUpdate()
1433 {
1434 auto dividerNode = GetDividerNode();
1435 CHECK_NULL_VOID(dividerNode);
1436 auto theme = NavigationGetTheme();
1437 CHECK_NULL_VOID(theme);
1438 dividerNode->GetRenderContext()->UpdateBackgroundColor(theme->GetNavigationDividerColor());
1439 }
1440
UpdatePreNavDesZIndex(const RefPtr<FrameNode> & preTopNavDestination,const RefPtr<FrameNode> & newTopNavDestination)1441 void NavigationPattern::UpdatePreNavDesZIndex(const RefPtr<FrameNode> &preTopNavDestination,
1442 const RefPtr<FrameNode> &newTopNavDestination)
1443 {
1444 auto replaceVal = navigationStack_->GetReplaceValue();
1445 if (replaceVal != 0 && preTopNavDestination && newTopNavDestination) {
1446 auto hostNode = AceType::DynamicCast<NavigationGroupNode>(GetHost());
1447 CHECK_NULL_VOID(hostNode);
1448 auto navigationContentNode = AceType::DynamicCast<FrameNode>(hostNode->GetContentNode());
1449 CHECK_NULL_VOID(navigationContentNode);
1450 auto newDesNodeContext = newTopNavDestination->GetRenderContext();
1451 CHECK_NULL_VOID(newDesNodeContext);
1452 std::optional<int32_t> newNodeZIndex = newDesNodeContext->GetZIndex();
1453 auto preDesNodeContext = preTopNavDestination->GetRenderContext();
1454 CHECK_NULL_VOID(preDesNodeContext);
1455 preDesNodeContext->UpdateZIndex(newNodeZIndex.value_or(0) - 1);
1456 navigationContentNode->RebuildRenderContextTree();
1457 auto context = PipelineContext::GetCurrentContext();
1458 CHECK_NULL_VOID(context);
1459 context->RequestFrame();
1460 }
1461 }
1462
SetNavigationStack(const RefPtr<NavigationStack> & navigationStack)1463 void NavigationPattern::SetNavigationStack(const RefPtr<NavigationStack>& navigationStack)
1464 {
1465 if (navigationStack_) {
1466 navigationStack_->SetOnStateChangedCallback(nullptr);
1467 }
1468 navigationStack_ = navigationStack;
1469 if (navigationStack_) {
1470 WeakPtr<NavigationPattern> weakPattern = WeakClaim(this);
1471 auto id = Container::CurrentId();
1472 auto callback = [weakPattern, id]() {
1473 ContainerScope scope(id);
1474 auto pattern = weakPattern.Upgrade();
1475 CHECK_NULL_VOID(pattern);
1476 if (pattern->NeedSyncWithJsStackMarked()) {
1477 return;
1478 }
1479
1480 pattern->MarkNeedSyncWithJsStack();
1481 auto context = PipelineContext::GetCurrentContext();
1482 CHECK_NULL_VOID(context);
1483 context->AddBuildFinishCallBack([weakPattern]() {
1484 auto pattern = weakPattern.Upgrade();
1485 CHECK_NULL_VOID(pattern);
1486 pattern->SyncWithJsStackIfNeeded();
1487 auto host = pattern->GetHost();
1488 CHECK_NULL_VOID(host);
1489 host->MarkDirtyNode();
1490 });
1491 context->RequestFrame();
1492 };
1493 navigationStack_->SetOnStateChangedCallback(callback);
1494 }
1495 }
1496
GetParentNavigationPattern()1497 RefPtr<NavigationPattern> NavigationPattern::GetParentNavigationPattern()
1498 {
1499 RefPtr<UINode> node = GetHost();
1500 CHECK_NULL_RETURN(node, nullptr);
1501 node = node->GetParent();
1502 while (node) {
1503 if (node->GetTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
1504 break;
1505 }
1506 node = node->GetParent();
1507 }
1508 auto groupNode = AceType::DynamicCast<NavigationGroupNode>(node);
1509 CHECK_NULL_RETURN(groupNode, nullptr);
1510 return AceType::DynamicCast<NavigationPattern>(groupNode->GetPattern());
1511 }
1512
AttachNavigationStackToParent()1513 void NavigationPattern::AttachNavigationStackToParent()
1514 {
1515 CHECK_NULL_VOID(navigationStack_);
1516 auto parentPattern = GetParentNavigationPattern();
1517 CHECK_NULL_VOID(parentPattern);
1518 auto parentStack = parentPattern->GetNavigationStack();
1519 if (parentStack) {
1520 navigationStack_->OnAttachToParent(parentStack);
1521 }
1522 }
1523
DetachNavigationStackFromParent()1524 void NavigationPattern::DetachNavigationStackFromParent()
1525 {
1526 if (navigationStack_) {
1527 navigationStack_->OnDetachFromParent();
1528 }
1529 }
1530
DealTransitionVisibility(const RefPtr<FrameNode> & node,bool isVisible,bool isNavBar)1531 void NavigationPattern::DealTransitionVisibility(const RefPtr<FrameNode>& node, bool isVisible, bool isNavBar)
1532 {
1533 auto renderContext = node->GetRenderContext();
1534 if (!renderContext->HasDisappearTransition()) {
1535 auto layoutProperty = node->GetLayoutProperty();
1536 layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
1537 node->SetJSViewActive(isVisible);
1538 return;
1539 }
1540 auto layoutProperty = node->GetLayoutProperty();
1541 layoutProperty->UpdateVisibility(isVisible ? VisibleType::VISIBLE : VisibleType::INVISIBLE, true);
1542 renderContext->SetTransitionOutCallback([weakNode = WeakPtr<FrameNode>(node), isVisible, isNavBar] {
1543 auto curNode = weakNode.Upgrade();
1544 CHECK_NULL_VOID(curNode);
1545 if (isNavBar) {
1546 auto navBarNode = AceType::DynamicCast<NavBarNode>(curNode);
1547 if (navBarNode->GetTransitionType() != PageTransitionType::EXIT_PUSH) {
1548 return;
1549 }
1550 } else {
1551 auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(curNode);
1552 if (navDestinationNode->GetTransitionType() != PageTransitionType::EXIT_PUSH) {
1553 return;
1554 }
1555 }
1556 curNode->SetJSViewActive(isVisible);
1557 });
1558 }
1559
1560 } // namespace OHOS::Ace::NG
1561