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