• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
17 
18 #include <atomic>
19 
20 #include "base/log/dump_log.h"
21 #include "core/common/agingadapation/aging_adapation_dialog_theme.h"
22 #include "core/common/agingadapation/aging_adapation_dialog_util.h"
23 #include "core/common/container.h"
24 #include "core/components/theme/app_theme.h"
25 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
26 #include "core/components_ng/pattern/navigation/title_bar_layout_property.h"
27 #include "core/components_ng/pattern/navigation/title_bar_node.h"
28 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
29 #include "core/components_ng/pattern/navigation/navigation_toolbar_util.h"
30 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
31 #include "core/components_ng/pattern/text/text_layout_property.h"
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 std::atomic<uint64_t> g_navDestinationPatternNextAutoGenId = 0;
36 // titlebar ZINDEX
37 constexpr static int32_t DEFAULT_TITLEBAR_ZINDEX = 2;
38 constexpr float TRANSLATE_THRESHOLD = 26.0f;
39 const auto TRANSLATE_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 228.0f, 30.0f);
40 
BuildMenu(const RefPtr<NavDestinationGroupNode> & navDestinationGroupNode,const RefPtr<TitleBarNode> & titleBarNode)41 void BuildMenu(const RefPtr<NavDestinationGroupNode>& navDestinationGroupNode, const RefPtr<TitleBarNode>& titleBarNode)
42 {
43     if (navDestinationGroupNode->GetMenuNodeOperationValue(ChildNodeOperation::NONE) == ChildNodeOperation::REPLACE) {
44         titleBarNode->RemoveChild(titleBarNode->GetMenu());
45         titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
46     }
47     if (navDestinationGroupNode->GetPrevMenuIsCustomValue(false)) {
48         if (navDestinationGroupNode->GetMenuNodeOperationValue(ChildNodeOperation::NONE) == ChildNodeOperation::NONE) {
49             return;
50         }
51         titleBarNode->SetMenu(navDestinationGroupNode->GetMenu());
52         titleBarNode->AddChild(titleBarNode->GetMenu());
53         titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
54         navDestinationGroupNode->UpdateMenuNodeOperation(ChildNodeOperation::NONE);
55     } else {
56         navDestinationGroupNode->UpdateMenuNodeOperation(ChildNodeOperation::NONE);
57         auto navDestinationPattern = navDestinationGroupNode->GetPattern<NavDestinationPattern>();
58         CHECK_NULL_VOID(navDestinationPattern);
59         auto titleBarMenuItems = navDestinationPattern->GetTitleBarMenuItems();
60         auto toolBarMenuItems = navDestinationPattern->GetToolBarMenuItems();
61 
62         bool isButtonEnabled = false;
63         auto hub = navDestinationGroupNode->GetEventHub<EventHub>();
64         if (hub) {
65             isButtonEnabled = hub->IsEnabled();
66         }
67         if (navDestinationPattern->HasMenuNodeId()) {
68             auto menuNode = NavigationTitleUtil::CreateMenuItems(navDestinationPattern->GetMenuNodeId(),
69                 titleBarMenuItems, navDestinationGroupNode, isButtonEnabled, DES_FIELD,
70                 titleBarNode->GetInnerParentId(), false);
71             CHECK_NULL_VOID(menuNode);
72             navDestinationGroupNode->SetMenu(menuNode);
73         }
74 
75         titleBarMenuItems.insert(titleBarMenuItems.end(), toolBarMenuItems.begin(), toolBarMenuItems.end());
76         auto landscapeMenuNode = NavigationTitleUtil::CreateMenuItems(navDestinationPattern->GetLandscapeMenuNodeId(),
77             titleBarMenuItems, navDestinationGroupNode, isButtonEnabled, DES_FIELD, titleBarNode->GetInnerParentId(),
78             true);
79         CHECK_NULL_VOID(landscapeMenuNode);
80         navDestinationGroupNode->SetLandscapeMenu(landscapeMenuNode);
81     }
82 }
83 
GetTitleOrToolBarTranslateAndHeight(const RefPtr<FrameNode> & barNode,float & translate,float & height)84 bool GetTitleOrToolBarTranslateAndHeight(const RefPtr<FrameNode>& barNode, float& translate, float& height)
85 {
86     CHECK_NULL_RETURN(barNode, false);
87     auto renderContext = barNode->GetRenderContext();
88     CHECK_NULL_RETURN(renderContext, false);
89     auto options = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
90     translate = options.y.ConvertToPx();
91     height = renderContext->GetPaintRectWithoutTransform().Height();
92     return true;
93 }
94 }
95 
NavDestinationPattern(const RefPtr<ShallowBuilder> & shallowBuilder)96 NavDestinationPattern::NavDestinationPattern(const RefPtr<ShallowBuilder>& shallowBuilder)
97     : shallowBuilder_(shallowBuilder)
98 {
99     navDestinationId_ = g_navDestinationPatternNextAutoGenId.fetch_add(1);
100 }
101 
NavDestinationPattern()102 NavDestinationPattern::NavDestinationPattern()
103 {
104     navDestinationId_ = g_navDestinationPatternNextAutoGenId.fetch_add(1);
105 }
106 
~NavDestinationPattern()107 NavDestinationPattern::~NavDestinationPattern()
108 {
109     customNode_ = nullptr;
110     if (scrollableProcessor_) {
111         scrollableProcessor_->UnbindAllScrollers();
112     }
113 }
114 
OnActive()115 void NavDestinationPattern::OnActive()
116 {
117     Pattern::OnActive();
118     auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
119     CHECK_NULL_VOID(hostNode);
120     auto navDestinationContext = hostNode->GetRenderContext();
121     CHECK_NULL_VOID(navDestinationContext);
122     auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
123     CHECK_NULL_VOID(navDestinationLayoutProperty);
124     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
125     CHECK_NULL_VOID(titleBarNode);
126     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
127     CHECK_NULL_VOID(titleBarLayoutProperty);
128     if (navDestinationLayoutProperty->GetHideTitleBar().value_or(false)) {
129         titleBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
130     } else {
131         titleBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
132     }
133     titleBarNode->MarkModifyDone();
134 }
135 
OnModifyDone()136 void NavDestinationPattern::OnModifyDone()
137 {
138     Pattern::OnModifyDone();
139     auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
140     CHECK_NULL_VOID(hostNode);
141     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
142     CHECK_NULL_VOID(titleBarNode);
143     auto titleBarRenderContext = titleBarNode->GetRenderContext();
144     CHECK_NULL_VOID(titleBarRenderContext);
145     titleBarNode->SetInnerParentId(hostNode->GetInspectorId().value_or(""));
146     // set the titlebar to float on the top
147     titleBarRenderContext->UpdateZIndex(DEFAULT_TITLEBAR_ZINDEX);
148     auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
149     CHECK_NULL_VOID(navDestinationLayoutProperty);
150     UpdateHideBarProperty();
151     ExpandContentSafeAreaIfNeeded();
152     UpdateNameIfNeeded(hostNode);
153     UpdateBackgroundColorIfNeeded(hostNode);
154     bool needRunTitleBarAnimation = false;
155     MountTitleBar(hostNode, needRunTitleBarAnimation);
156     bool needRunToolBarAnimation = false;
157     NavigationToolbarUtil::MountToolBar(hostNode, needRunToolBarAnimation);
158     HandleTitleBarAndToolBarAnimation(hostNode, needRunTitleBarAnimation, needRunToolBarAnimation);
159     auto pipeline = hostNode->GetContext();
160     CHECK_NULL_VOID(pipeline);
161     if (GreatOrEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
162         auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
163         CHECK_NULL_VOID(titleBarPattern);
164         auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
165         CHECK_NULL_VOID(backButtonNode);
166         titleBarPattern->InitBackButtonLongPressEvent(backButtonNode);
167     }
168     if (scrollableProcessor_) {
169         scrollableProcessor_->UpdateBindingRelation();
170     }
171     auto renderContext = hostNode->GetRenderContext();
172     CHECK_NULL_VOID(renderContext);
173     hostNode->UpdateUserSetOpacity(renderContext->GetOpacity().value_or(1.0f));
174 }
175 
OnLanguageConfigurationUpdate()176 void NavDestinationPattern::OnLanguageConfigurationUpdate()
177 {
178     if (isRightToLeft_ == AceApplicationInfo::GetInstance().IsRightToLeft()) {
179         return;
180     }
181     isRightToLeft_ = AceApplicationInfo::GetInstance().IsRightToLeft();
182     auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
183     CHECK_NULL_VOID(hostNode);
184     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
185     CHECK_NULL_VOID(titleBarNode);
186     titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
187 }
188 
UpdateNameIfNeeded(RefPtr<NavDestinationGroupNode> & hostNode)189 void NavDestinationPattern::UpdateNameIfNeeded(RefPtr<NavDestinationGroupNode>& hostNode)
190 {
191     if (!name_.empty()) {
192         return;
193     }
194 
195     if (hostNode->GetInspectorId().has_value()) {
196         name_ = hostNode->GetInspectorIdValue();
197     } else {
198         name_ = std::to_string(GetHost()->GetId());
199     }
200     auto pathInfo = GetNavPathInfo();
201     if (pathInfo) {
202         pathInfo->SetName(name_);
203     }
204 }
205 
UpdateBackgroundColorIfNeeded(RefPtr<NavDestinationGroupNode> & hostNode)206 void NavDestinationPattern::UpdateBackgroundColorIfNeeded(RefPtr<NavDestinationGroupNode>& hostNode)
207 {
208     auto renderContext = hostNode->GetRenderContext();
209     CHECK_NULL_VOID(renderContext);
210     if (IsUserDefinedBgColor()) {
211         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "User defined Background color: %{public}s",
212             renderContext->GetBackgroundColor()->ColorToString().c_str());
213         return;
214     }
215     if (hostNode->GetNavDestinationMode() == NavDestinationMode::DIALOG) {
216         renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
217         TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Set dialog background color: %{public}s",
218             renderContext->GetBackgroundColor()->ColorToString().c_str());
219         return;
220     }
221     auto pipelineContext = PipelineContext::GetCurrentContext();
222     if (!pipelineContext) {
223         return;
224     }
225     auto theme = pipelineContext->GetTheme<AppTheme>();
226     if (!theme) {
227         return;
228     }
229     renderContext->UpdateBackgroundColor(theme->GetBackgroundColor());
230     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "Default background color: %{public}s",
231         renderContext->GetBackgroundColor()->ColorToString().c_str());
232 }
233 
MountTitleBar(RefPtr<NavDestinationGroupNode> & hostNode,bool & needRunTitleBarAnimation)234 void NavDestinationPattern::MountTitleBar(
235     RefPtr<NavDestinationGroupNode>& hostNode, bool& needRunTitleBarAnimation)
236 {
237     needRunTitleBarAnimation = false;
238     auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
239     CHECK_NULL_VOID(navDestinationLayoutProperty);
240     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
241     CHECK_NULL_VOID(titleBarNode);
242     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
243     CHECK_NULL_VOID(titleBarLayoutProperty);
244 
245     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
246     if (backButtonNode) {
247         auto backButtonLayoutProperty = backButtonNode->GetLayoutProperty();
248         CHECK_NULL_VOID(backButtonLayoutProperty);
249         backButtonLayoutProperty->UpdateVisibility(
250             navDestinationLayoutProperty->GetHideBackButtonValue(false) ? VisibleType::GONE : VisibleType::VISIBLE);
251     }
252     if (navDestinationLayoutProperty->HasNoPixMap()) {
253         if (navDestinationLayoutProperty->HasImageSource()) {
254             titleBarLayoutProperty->UpdateImageSource(navDestinationLayoutProperty->GetImageSourceValue());
255         }
256         if (navDestinationLayoutProperty->HasPixelMap()) {
257             titleBarLayoutProperty->UpdatePixelMap(navDestinationLayoutProperty->GetPixelMapValue());
258         }
259         titleBarLayoutProperty->UpdateNoPixMap(navDestinationLayoutProperty->GetNoPixMapValue());
260     }
261     bool hideTitleBar = navDestinationLayoutProperty->GetHideTitleBarValue(false);
262     BuildMenu(hostNode, titleBarNode);
263 
264     auto navDesIndex = hostNode->GetIndex();
265     if (navDesIndex == 0) {
266         navDestinationLayoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
267         titleBarLayoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
268     }
269 
270     if (currHideTitleBar_.has_value() && currHideTitleBar_.value() != hideTitleBar && hideTitleBar) {
271         /**
272          * we need reset translate&opacity of titleBar when state change from show to hide. @sa EnableTitleBarSwipe
273          */
274         NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(hostNode, titleBarNode, 0.0f, true);
275     }
276     // At the initial state, animation is not required.
277     if (!currHideTitleBar_.has_value() || !navDestinationLayoutProperty->GetIsAnimatedTitleBarValue(false)) {
278         currHideTitleBar_ = hideTitleBar;
279         HideOrShowTitleBarImmediately(hostNode, hideTitleBar);
280         return;
281     }
282 
283     titleBarNode->MarkModifyDone();
284     titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
285 
286     // Animation is needed only when the status changed.
287     needRunTitleBarAnimation = currHideTitleBar_.value() != hideTitleBar;
288     currHideTitleBar_ = hideTitleBar;
289 }
290 
GetBackButtonState()291 bool NavDestinationPattern::GetBackButtonState()
292 {
293     auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
294     CHECK_NULL_RETURN(hostNode, false);
295     auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
296     CHECK_NULL_RETURN(navDestinationLayoutProperty, false);
297 
298     auto translateState = navDestinationLayoutProperty->GetTitleBarTranslateStateValue(BarTranslateState::NONE);
299     if (navDestinationLayoutProperty->GetHideTitleBarValue(false) && translateState == BarTranslateState::NONE) {
300         return false;
301     }
302     // get navigation node
303     auto parent = AceType::DynamicCast<FrameNode>(hostNode->GetParent());
304     RefPtr<NavigationGroupNode> navigationNode;
305     while (parent && !parent->IsRootNode()) {
306         navigationNode = AceType::DynamicCast<NavigationGroupNode>(parent);
307         if (navigationNode) {
308             break;
309         }
310         parent = AceType::DynamicCast<FrameNode>(parent->GetParent());
311     }
312     if (!navigationNode) {
313         TAG_LOGW(AceLogTag::ACE_NAVIGATION, "can't find navigation node");
314         return false;
315     }
316     auto navigationLayoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
317     CHECK_NULL_RETURN(navigationLayoutProperty, false);
318     auto pattern = navigationNode->GetPattern<NavigationPattern>();
319     auto stack = pattern->GetNavigationStack();
320     auto index = stack->FindIndex(name_, customNode_, true);
321     bool showBackButton = true;
322     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
323     if (navDestinationLayoutProperty->GetHideBackButtonValue(false)) {
324         showBackButton = false;
325     }
326     if (index == 0 && (pattern->GetNavigationMode() == NavigationMode::SPLIT ||
327         navigationLayoutProperty->GetHideNavBarValue(false))) {
328         showBackButton = false;
329     }
330     auto isCustomTitle = hostNode->GetPrevTitleIsCustomValue(false);
331     if (isCustomTitle) {
332         return showBackButton;
333     }
334     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
335     CHECK_NULL_RETURN(titleBarPattern, showBackButton);
336     if (titleBarPattern->IsFontSizeSettedByDeveloper()) {
337         return showBackButton;
338     }
339     auto titleNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
340     CHECK_NULL_RETURN(titleNode, showBackButton);
341     auto theme = NavigationGetTheme();
342     CHECK_NULL_RETURN(theme, showBackButton);
343     auto textLayoutProperty = titleNode->GetLayoutProperty<TextLayoutProperty>();
344     auto currentFontSize = textLayoutProperty->GetAdaptMaxFontSizeValue(Dimension(0.0, DimensionUnit::FP));
345     auto targetFontSize = showBackButton ? theme->GetTitleFontSizeMin() : theme->GetTitleFontSize();
346     if (targetFontSize == currentFontSize) {
347         return showBackButton;
348     }
349     textLayoutProperty->UpdateAdaptMaxFontSize(targetFontSize);
350     textLayoutProperty->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
351     return showBackButton;
352 }
353 
OnAttachToFrameNode()354 void NavDestinationPattern::OnAttachToFrameNode()
355 {
356     auto host = GetHost();
357     CHECK_NULL_VOID(host);
358     if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
359         SafeAreaExpandOpts opts = { .type = SAFE_AREA_TYPE_SYSTEM | SAFE_AREA_TYPE_CUTOUT,
360             .edges = SAFE_AREA_EDGE_ALL };
361         host->GetLayoutProperty()->UpdateSafeAreaExpandOpts(opts);
362     }
363     isRightToLeft_ = AceApplicationInfo::GetInstance().IsRightToLeft();
364     auto id = host->GetId();
365     auto pipeline = host->GetContext();
366     CHECK_NULL_VOID(pipeline);
367     pipeline->AddWindowStateChangedCallback(id);
368     pipeline->AddWindowSizeChangeCallback(id);
369 }
370 
OnDetachFromFrameNode(FrameNode * frameNode)371 void NavDestinationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
372 {
373     CHECK_NULL_VOID(frameNode);
374     auto id = frameNode->GetId();
375     auto pipeline = frameNode->GetContext();
376     CHECK_NULL_VOID(pipeline);
377     pipeline->RemoveWindowStateChangedCallback(id);
378     pipeline->RemoveWindowSizeChangeCallback(id);
379 }
380 
DumpInfo()381 void NavDestinationPattern::DumpInfo()
382 {
383     DumpLog::GetInstance().AddDesc(std::string("name: ").append(name_));
384 }
385 
OverlayOnBackPressed()386 bool NavDestinationPattern::OverlayOnBackPressed()
387 {
388     CHECK_NULL_RETURN(overlayManager_, false);
389     if (overlayManager_->isCurrentNodeProcessRemoveOverlay(GetHost(), false)) {
390         return overlayManager_->RemoveOverlay(true);
391     }
392     return false;
393 }
394 
NeedIgnoreKeyboard()395 bool NavDestinationPattern::NeedIgnoreKeyboard()
396 {
397     auto layoutProperty = GetLayoutProperty<NavDestinationLayoutProperty>();
398     CHECK_NULL_RETURN(layoutProperty, false);
399     auto& opts = layoutProperty->GetSafeAreaExpandOpts();
400     if (opts && (opts->type & SAFE_AREA_TYPE_KEYBOARD) && (opts->edges & SAFE_AREA_EDGE_BOTTOM)) {
401         return true;
402     }
403     return false;
404 }
405 
OnFontScaleConfigurationUpdate()406 void NavDestinationPattern::OnFontScaleConfigurationUpdate()
407 {
408     auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
409     CHECK_NULL_VOID(hostNode);
410     auto pipeline = hostNode->GetContext();
411     CHECK_NULL_VOID(pipeline);
412     auto titleBarUINode = hostNode->GetTitleBarNode();
413     auto titleBarNode = AceType::DynamicCast<TitleBarNode>(titleBarUINode);
414     CHECK_NULL_VOID(titleBarNode);
415     auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
416     CHECK_NULL_VOID(backButtonNode);
417     if (LessNotEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
418         auto gestureHub = backButtonNode->GetOrCreateGestureEventHub();
419         CHECK_NULL_VOID(gestureHub);
420         gestureHub->SetLongPressEvent(nullptr);
421         auto longPressRecognizer = gestureHub->GetLongPressRecognizer();
422         CHECK_NULL_VOID(longPressRecognizer);
423         longPressRecognizer->SetOnActionEnd(nullptr);
424         return;
425     }
426     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
427     CHECK_NULL_VOID(titleBarPattern);
428     titleBarPattern->InitBackButtonLongPressEvent(backButtonNode);
429 }
430 
SetSystemBarStyle(const RefPtr<SystemBarStyle> & style)431 void NavDestinationPattern::SetSystemBarStyle(const RefPtr<SystemBarStyle>& style)
432 {
433     auto host = GetHost();
434     CHECK_NULL_VOID(host);
435     auto pipeline = host->GetContext();
436     CHECK_NULL_VOID(pipeline);
437     auto windowManager = pipeline->GetWindowManager();
438     CHECK_NULL_VOID(windowManager);
439     if (!backupStyle_.has_value()) {
440         backupStyle_ = windowManager->GetSystemBarStyle();
441     }
442     currStyle_ = style;
443     auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navigationNode_.Upgrade());
444     CHECK_NULL_VOID(navigationNode);
445     auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
446     if (navigationPattern->IsFullPageNavigation() && navigationPattern->IsTopNavDestination(host)) {
447         if (currStyle_.value() != nullptr) {
448             windowManager->SetSystemBarStyle(currStyle_.value());
449         } else {
450             navigationPattern->TryRestoreSystemBarStyle(windowManager);
451         }
452     }
453 }
454 
GetTitlebarZIndex() const455 int32_t NavDestinationPattern::GetTitlebarZIndex() const
456 {
457     return DEFAULT_TITLEBAR_ZINDEX;
458 }
459 
OnWindowHide()460 void NavDestinationPattern::OnWindowHide()
461 {
462     CHECK_NULL_VOID(navDestinationContext_);
463     auto navPathInfo = navDestinationContext_->GetNavPathInfo();
464     CHECK_NULL_VOID(navPathInfo);
465     if (!navPathInfo->GetIsEntry()) {
466         return;
467     }
468     TAG_LOGI(AceLogTag::ACE_NAVIGATION, "window lifecycle change to hide, clear navDestination entry tag");
469     navPathInfo->SetIsEntry(false);
470     auto stack = GetNavigationStack().Upgrade();
471     CHECK_NULL_VOID(stack);
472     auto index = navDestinationContext_->GetIndex();
473     stack->SetIsEntryByIndex(index, false);
474 }
475 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)476 void NavDestinationPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
477 {
478     auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
479     CHECK_NULL_VOID(navDestinationGroupNode);
480     if (preWidth_.has_value() && preWidth_.value() != width) {
481         AbortBarAnimation();
482     }
483     preWidth_ = width;
484     // change menu num in landscape and orientation
485     do {
486         if (navDestinationGroupNode->GetPrevMenuIsCustomValue(false)) {
487             break;
488         }
489         auto targetNum = SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE ? MAX_MENU_NUM_LARGE
490                                                                                                   : MAX_MENU_NUM_SMALL;
491         if (targetNum == maxMenuNums_) {
492             break;
493         }
494         maxMenuNums_ = targetNum;
495         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationGroupNode->GetTitleBarNode());
496         CHECK_NULL_VOID(titleBarNode);
497         BuildMenu(navDestinationGroupNode, titleBarNode);
498         titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
499     } while (0);
500 }
501 
UpdateTitleAndToolBarHiddenOffset(float offset)502 void NavDestinationPattern::UpdateTitleAndToolBarHiddenOffset(float offset)
503 {
504     CancelShowTitleAndToolBarTask();
505     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
506     CHECK_NULL_VOID(nodeBase);
507     if (EnableTitleBarSwipe(nodeBase)) {
508         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
509         UpdateBarHiddenOffset(nodeBase, titleBarNode, offset, true);
510     }
511     if (EnableToolBarSwipe(nodeBase)) {
512         auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
513         UpdateBarHiddenOffset(nodeBase, toolBarNode, offset, false);
514     }
515 }
516 
CancelShowTitleAndToolBarTask()517 void NavDestinationPattern::CancelShowTitleAndToolBarTask()
518 {
519     if (titleBarSwipeContext_.showBarTask) {
520         titleBarSwipeContext_.showBarTask.Cancel();
521         titleBarSwipeContext_.showBarTask.Reset(nullptr);
522     }
523     if (toolBarSwipeContext_.showBarTask) {
524         toolBarSwipeContext_.showBarTask.Cancel();
525         toolBarSwipeContext_.showBarTask.Reset(nullptr);
526     }
527 }
528 
ResetTitleAndToolBarState()529 void NavDestinationPattern::ResetTitleAndToolBarState()
530 {
531     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
532     CHECK_NULL_VOID(nodeBase);
533     if (EnableTitleBarSwipe(nodeBase)) {
534         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
535         ResetBarState(nodeBase, titleBarNode, true);
536     }
537     if (EnableToolBarSwipe(nodeBase)) {
538         auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
539         ResetBarState(nodeBase, toolBarNode, false);
540     }
541 }
542 
ResetBarState(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,bool isTitle)543 void NavDestinationPattern::ResetBarState(const RefPtr<NavDestinationNodeBase>& nodeBase,
544     const RefPtr<FrameNode>& barNode, bool isTitle)
545 {
546     CHECK_NULL_VOID(nodeBase);
547     CHECK_NULL_VOID(barNode);
548     auto& ctx = GetSwipeContext(isTitle);
549     if (ctx.isBarHiding || ctx.isBarShowing) {
550         return;
551     }
552 
553     float translate = 0.0f;
554     float barHeight = 0.0f;
555     if (!GetTitleOrToolBarTranslateAndHeight(barNode, translate, barHeight) || NearZero(barHeight)) {
556         return;
557     }
558 
559     auto threshold = Dimension(TRANSLATE_THRESHOLD, DimensionUnit::VP).ConvertToPx();
560     float halfBarHeight = barHeight / 2.0f;
561     if (GreatOrEqual(threshold, halfBarHeight)) {
562         threshold = halfBarHeight;
563     }
564     float showAreaHeight = barHeight - std::abs(translate);
565     if (GreatNotEqual(showAreaHeight, 0.0f) && LessNotEqual(showAreaHeight, threshold)) {
566         /**
567          * Scroll to show a small portion of the titleBar&toolBar,
568          * but the height of shownArea is less than the threshold,
569          * it needs to be restored to the hidden state.
570          */
571         StartHideOrShowBarInner(nodeBase, barHeight, translate, isTitle, true);
572     } else if (GreatOrEqual(showAreaHeight, barHeight - threshold) && LessNotEqual(showAreaHeight, barHeight)) {
573         /**
574          * Scroll to hide a small portion of the titleBar&toolBar,
575          * but the height of hiddenArea is less than the threshold,
576          * it needs to be restored to the shown state.
577          */
578         StartHideOrShowBarInner(nodeBase, barHeight, translate, isTitle, false);
579     }
580 }
581 
EnableTitleBarSwipe(const RefPtr<NavDestinationNodeBase> & nodeBase)582 bool NavDestinationPattern::EnableTitleBarSwipe(const RefPtr<NavDestinationNodeBase>& nodeBase)
583 {
584     CHECK_NULL_RETURN(nodeBase, false);
585     auto property = nodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
586     CHECK_NULL_RETURN(property, false);
587     return !property->GetHideTitleBarValue(false);
588 }
589 
EnableToolBarSwipe(const RefPtr<NavDestinationNodeBase> & nodeBase)590 bool NavDestinationPattern::EnableToolBarSwipe(const RefPtr<NavDestinationNodeBase>& nodeBase)
591 {
592     CHECK_NULL_RETURN(nodeBase, false);
593     auto property = nodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
594     CHECK_NULL_RETURN(property, false);
595     return !property->GetHideToolBarValue(false);
596 }
597 
UpdateBarHiddenOffset(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,float offset,bool isTitle)598 void NavDestinationPattern::UpdateBarHiddenOffset(
599     const RefPtr<NavDestinationNodeBase>& nodeBase, const RefPtr<FrameNode>& barNode, float offset, bool isTitle)
600 {
601     CHECK_NULL_VOID(nodeBase);
602     CHECK_NULL_VOID(barNode);
603     auto& ctx = GetSwipeContext(isTitle);
604     if (ctx.isBarShowing || ctx.isBarHiding) {
605         return;
606     }
607 
608     float preTranslate = 0.0f;
609     float barHeight = 0.0f;
610     if (!GetTitleOrToolBarTranslateAndHeight(barNode, preTranslate, barHeight) || NearZero(barHeight)) {
611         return;
612     }
613 
614     float newTranslate = 0.0f;
615     if (isTitle) {
616         newTranslate = std::clamp(preTranslate - offset, -barHeight, 0.0f);
617     } else {
618         newTranslate = std::clamp(preTranslate + offset, 0.0f, barHeight);
619     }
620     NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, newTranslate, isTitle);
621 
622     auto threshold = Dimension(TRANSLATE_THRESHOLD, DimensionUnit::VP).ConvertToPx();
623     float halfBarHeight = barHeight / 2.0f;
624     if (GreatOrEqual(threshold, halfBarHeight)) {
625         threshold = halfBarHeight;
626     }
627     if (Positive(offset) && LessNotEqual(std::abs(preTranslate), threshold) &&
628         GreatOrEqual(std::abs(newTranslate), threshold)) {
629         // When the scrolling up distance exceeds the threshold, it is necessary to start the hide animation.
630         StartHideOrShowBarInner(nodeBase, barHeight, newTranslate, isTitle, true);
631     } else if (Negative(offset) && LessNotEqual(barHeight - std::abs(preTranslate), threshold) &&
632         GreatOrEqual(barHeight - std::abs(newTranslate), threshold)) {
633         // When the scrolling down distance exceeds the threshold, it is necessary to start the show animation.
634         StartHideOrShowBarInner(nodeBase, barHeight, newTranslate, isTitle, false);
635     }
636 }
637 
ShowTitleAndToolBar()638 void NavDestinationPattern::ShowTitleAndToolBar()
639 {
640     auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
641     CHECK_NULL_VOID(nodeBase);
642     if (EnableTitleBarSwipe(nodeBase)) {
643         auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
644         float translate = 0.0f;
645         float barHeight = 0.0f;
646         if (GetTitleOrToolBarTranslateAndHeight(titleBarNode, translate, barHeight)) {
647             if (titleBarSwipeContext_.showBarTask) {
648                 titleBarSwipeContext_.showBarTask.Cancel();
649                 titleBarSwipeContext_.showBarTask.Reset(nullptr);
650             }
651             StopHideBarIfNeeded(translate, true);
652             StartHideOrShowBarInner(nodeBase, barHeight, translate, true, false);
653         }
654     }
655     if (EnableToolBarSwipe(nodeBase)) {
656         auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
657         float translate = 0.0f;
658         float barHeight = 0.0f;
659         if (GetTitleOrToolBarTranslateAndHeight(toolBarNode, translate, barHeight)) {
660             if (toolBarSwipeContext_.showBarTask) {
661                 toolBarSwipeContext_.showBarTask.Cancel();
662                 toolBarSwipeContext_.showBarTask.Reset(nullptr);
663             }
664             StopHideBarIfNeeded(translate, false);
665             StartHideOrShowBarInner(nodeBase, barHeight, translate, false, false);
666         }
667     }
668 }
669 
StartHideOrShowBarInner(const RefPtr<NavDestinationNodeBase> & nodeBase,float barHeight,float curTranslate,bool isTitle,bool isHide)670 void NavDestinationPattern::StartHideOrShowBarInner(
671     const RefPtr<NavDestinationNodeBase>& nodeBase, float barHeight, float curTranslate, bool isTitle, bool isHide)
672 {
673     CHECK_NULL_VOID(nodeBase);
674     auto barNode = GetBarNode(nodeBase, isTitle);
675     CHECK_NULL_VOID(barNode);
676 
677     auto propertyCallback = [weak = WeakClaim(this), barHeight, isTitle, isHide]() {
678         auto pattern = weak.Upgrade();
679         CHECK_NULL_VOID(pattern);
680         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
681         CHECK_NULL_VOID(nodeBase);
682         auto barNode = pattern->GetBarNode(nodeBase, isTitle);
683         CHECK_NULL_VOID(barNode);
684         float translate = isHide ? (isTitle ? -barHeight : barHeight) : 0.0f;
685         NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, translate, isTitle);
686     };
687     auto finishCallback = [weak = WeakClaim(this), isTitle, isHide]() {
688         auto pattern = weak.Upgrade();
689         CHECK_NULL_VOID(pattern);
690         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
691         CHECK_NULL_VOID(nodeBase);
692         auto barNode = pattern->GetBarNode(nodeBase, isTitle);
693         CHECK_NULL_VOID(barNode);
694         auto& ctx = pattern->GetSwipeContext(isTitle);
695         if (isHide) {
696             ctx.isBarHiding = false;
697         } else {
698             ctx.isBarShowing = false;
699         }
700     };
701     AnimationOption option;
702     option.SetCurve(TRANSLATE_CURVE);
703     auto& ctx = GetSwipeContext(isTitle);
704     if (isHide) {
705         ctx.isBarHiding = true;
706     } else {
707         ctx.isBarShowing = true;
708     }
709     NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, curTranslate, isTitle);
710     AnimationUtils::Animate(option, propertyCallback, finishCallback);
711 }
712 
StopHideBarIfNeeded(float curTranslate,bool isTitle)713 void NavDestinationPattern::StopHideBarIfNeeded(float curTranslate, bool isTitle)
714 {
715     auto& ctx = GetSwipeContext(isTitle);
716     if (!ctx.isBarHiding) {
717         return;
718     }
719 
720     auto propertyCallback = [weak = WeakClaim(this), isTitle, curTranslate]() {
721         auto pattern = weak.Upgrade();
722         CHECK_NULL_VOID(pattern);
723         auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
724         CHECK_NULL_VOID(nodeBase);
725         auto barNode = pattern->GetBarNode(nodeBase, isTitle);
726         CHECK_NULL_VOID(barNode);
727         NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, curTranslate, isTitle);
728     };
729     AnimationOption option;
730     option.SetDuration(0);
731     option.SetCurve(Curves::LINEAR);
732     AnimationUtils::Animate(option, propertyCallback);
733     ctx.isBarHiding = false;
734 }
735 
GetBarNode(const RefPtr<NavDestinationNodeBase> & nodeBase,bool isTitle)736 RefPtr<FrameNode> NavDestinationPattern::GetBarNode(const RefPtr<NavDestinationNodeBase>& nodeBase, bool isTitle)
737 {
738     CHECK_NULL_RETURN(nodeBase, nullptr);
739     return isTitle ? AceType::DynamicCast<FrameNode>(nodeBase->GetTitleBarNode())
740                    : AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarNode());
741 }
742 } // namespace OHOS::Ace::NG
743