• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/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