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 "base/log/dump_log.h"
19 #include "core/common/agingadapation/aging_adapation_dialog_theme.h"
20 #include "core/common/agingadapation/aging_adapation_dialog_util.h"
21 #include "core/components/theme/app_theme.h"
22 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
23 #include "core/components_ng/pattern/navigation/navigation_title_util.h"
24 #include "core/components_ng/pattern/navigation/navigation_toolbar_util.h"
25 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 std::atomic<uint64_t> g_navDestinationPatternNextAutoGenId = 0;
30 // titlebar ZINDEX
31 constexpr static int32_t DEFAULT_TITLEBAR_ZINDEX = 2;
32 constexpr float TRANSLATE_THRESHOLD = 26.0f;
33 const auto TRANSLATE_CURVE = AceType::MakeRefPtr<InterpolatingSpring>(0.0f, 1.0f, 228.0f, 30.0f);
34
BuildMenu(const RefPtr<NavDestinationGroupNode> & navDestinationGroupNode,const RefPtr<TitleBarNode> & titleBarNode)35 void BuildMenu(const RefPtr<NavDestinationGroupNode>& navDestinationGroupNode, const RefPtr<TitleBarNode>& titleBarNode)
36 {
37 if (navDestinationGroupNode->GetMenuNodeOperationValue(ChildNodeOperation::NONE) == ChildNodeOperation::REPLACE) {
38 titleBarNode->RemoveChild(titleBarNode->GetMenu());
39 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
40 }
41 if (navDestinationGroupNode->GetPrevMenuIsCustomValue(false)) {
42 if (navDestinationGroupNode->GetMenuNodeOperationValue(ChildNodeOperation::NONE) == ChildNodeOperation::NONE) {
43 return;
44 }
45 titleBarNode->SetMenu(navDestinationGroupNode->GetMenu());
46 titleBarNode->AddChild(titleBarNode->GetMenu());
47 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
48 navDestinationGroupNode->UpdateMenuNodeOperation(ChildNodeOperation::NONE);
49 } else {
50 navDestinationGroupNode->UpdateMenuNodeOperation(ChildNodeOperation::NONE);
51 auto navDestinationPattern = navDestinationGroupNode->GetPattern<NavDestinationPattern>();
52 CHECK_NULL_VOID(navDestinationPattern);
53 auto titleBarMenuItems = navDestinationPattern->GetTitleBarMenuItems();
54 auto toolBarMenuItems = navDestinationPattern->GetToolBarMenuItems();
55
56 bool isButtonEnabled = false;
57 auto hub = navDestinationGroupNode->GetEventHub<EventHub>();
58 if (hub) {
59 isButtonEnabled = hub->IsEnabled();
60 }
61 if (navDestinationPattern->HasMenuNodeId()) {
62 auto menuNode = NavigationTitleUtil::CreateMenuItems(navDestinationPattern->GetMenuNodeId(),
63 titleBarMenuItems, navDestinationGroupNode, isButtonEnabled, DES_FIELD,
64 titleBarNode->GetInnerParentId(), false);
65 CHECK_NULL_VOID(menuNode);
66 navDestinationGroupNode->SetMenu(menuNode);
67 }
68
69 titleBarMenuItems.insert(titleBarMenuItems.end(), toolBarMenuItems.begin(), toolBarMenuItems.end());
70 auto landscapeMenuNode = NavigationTitleUtil::CreateMenuItems(navDestinationPattern->GetLandscapeMenuNodeId(),
71 titleBarMenuItems, navDestinationGroupNode, isButtonEnabled, DES_FIELD, titleBarNode->GetInnerParentId(),
72 true);
73 CHECK_NULL_VOID(landscapeMenuNode);
74 navDestinationGroupNode->SetLandscapeMenu(landscapeMenuNode);
75 }
76 }
77
GetTitleOrToolBarTranslateAndHeight(const RefPtr<FrameNode> & barNode,float & translate,float & height)78 bool GetTitleOrToolBarTranslateAndHeight(const RefPtr<FrameNode>& barNode, float& translate, float& height)
79 {
80 CHECK_NULL_RETURN(barNode, false);
81 auto renderContext = barNode->GetRenderContext();
82 CHECK_NULL_RETURN(renderContext, false);
83 auto options = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
84 translate = options.y.ConvertToPx();
85 height = renderContext->GetPaintRectWithoutTransform().Height();
86 return true;
87 }
88 }
89
NavDestinationPattern(const RefPtr<ShallowBuilder> & shallowBuilder)90 NavDestinationPattern::NavDestinationPattern(const RefPtr<ShallowBuilder>& shallowBuilder)
91 : shallowBuilder_(shallowBuilder)
92 {
93 navDestinationId_ = g_navDestinationPatternNextAutoGenId.fetch_add(1);
94 }
95
NavDestinationPattern()96 NavDestinationPattern::NavDestinationPattern()
97 {
98 navDestinationId_ = g_navDestinationPatternNextAutoGenId.fetch_add(1);
99 }
100
~NavDestinationPattern()101 NavDestinationPattern::~NavDestinationPattern()
102 {
103 customNode_ = nullptr;
104 if (scrollableProcessor_) {
105 scrollableProcessor_->UnbindAllScrollers();
106 }
107 }
108
OnActive()109 void NavDestinationPattern::OnActive()
110 {
111 Pattern::OnActive();
112 auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
113 CHECK_NULL_VOID(hostNode);
114 auto navDestinationContext = hostNode->GetRenderContext();
115 CHECK_NULL_VOID(navDestinationContext);
116 auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
117 CHECK_NULL_VOID(navDestinationLayoutProperty);
118 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
119 CHECK_NULL_VOID(titleBarNode);
120 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
121 CHECK_NULL_VOID(titleBarLayoutProperty);
122 if (navDestinationLayoutProperty->GetHideTitleBar().value_or(false)) {
123 titleBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
124 } else {
125 titleBarLayoutProperty->UpdateVisibility(VisibleType::VISIBLE);
126 }
127 titleBarNode->MarkModifyDone();
128 }
129
OnModifyDone()130 void NavDestinationPattern::OnModifyDone()
131 {
132 Pattern::OnModifyDone();
133 auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
134 CHECK_NULL_VOID(hostNode);
135 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
136 CHECK_NULL_VOID(titleBarNode);
137 auto titleBarRenderContext = titleBarNode->GetRenderContext();
138 CHECK_NULL_VOID(titleBarRenderContext);
139 titleBarNode->SetInnerParentId(hostNode->GetInspectorId().value_or(""));
140 // set the titlebar to float on the top
141 titleBarRenderContext->UpdateZIndex(DEFAULT_TITLEBAR_ZINDEX);
142 auto navDestinationLayoutProperty = hostNode->GetLayoutProperty<NavDestinationLayoutProperty>();
143 CHECK_NULL_VOID(navDestinationLayoutProperty);
144 UpdateHideBarProperty();
145 ExpandContentSafeAreaIfNeeded();
146 UpdateNameIfNeeded(hostNode);
147 UpdateBackgroundColorIfNeeded(hostNode);
148 bool needRunTitleBarAnimation = false;
149 MountTitleBar(hostNode, needRunTitleBarAnimation);
150 bool needRunToolBarAnimation = false;
151 NavigationToolbarUtil::MountToolBar(hostNode, needRunToolBarAnimation);
152 HandleTitleBarAndToolBarAnimation(hostNode, needRunTitleBarAnimation, needRunToolBarAnimation);
153 auto pipeline = hostNode->GetContext();
154 CHECK_NULL_VOID(pipeline);
155 if (GreatOrEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
156 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
157 CHECK_NULL_VOID(titleBarPattern);
158 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
159 CHECK_NULL_VOID(backButtonNode);
160 titleBarPattern->InitBackButtonLongPressEvent(backButtonNode);
161 }
162 if (scrollableProcessor_) {
163 scrollableProcessor_->UpdateBindingRelation();
164 }
165 auto renderContext = hostNode->GetRenderContext();
166 CHECK_NULL_VOID(renderContext);
167 hostNode->UpdateUserSetOpacity(renderContext->GetOpacity().value_or(1.0f));
168 }
169
OnLanguageConfigurationUpdate()170 void NavDestinationPattern::OnLanguageConfigurationUpdate()
171 {
172 if (isRightToLeft_ == AceApplicationInfo::GetInstance().IsRightToLeft()) {
173 return;
174 }
175 isRightToLeft_ = AceApplicationInfo::GetInstance().IsRightToLeft();
176 auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
177 CHECK_NULL_VOID(hostNode);
178 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(hostNode->GetTitleBarNode());
179 CHECK_NULL_VOID(titleBarNode);
180 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
181 auto backButtonUINode = titleBarNode->GetBackButton();
182 auto backButtonNode = AceType::DynamicCast<FrameNode>(backButtonUINode);
183 CHECK_NULL_VOID(backButtonNode);
184 auto imageNode = backButtonNode->GetFirstChild();
185 CHECK_NULL_VOID(imageNode);
186 imageNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
187 }
188
UpdateNameIfNeeded(RefPtr<NavDestinationGroupNode> & hostNode)189 void NavDestinationPattern::UpdateNameIfNeeded(RefPtr<NavDestinationGroupNode>& hostNode)
190 {
191 if (!name_.empty()) {
192 return;
193 }
194 CHECK_NULL_VOID(hostNode);
195 if (hostNode->GetInspectorId().has_value()) {
196 name_ = hostNode->GetInspectorIdValue();
197 } else {
198 name_ = std::to_string(hostNode->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
368 pipeline->AddWindowStateChangedCallback(id);
369 pipeline->AddWindowSizeChangeCallback(id);
370 pipeline->GetMemoryManager()->AddRecyclePageNode(host);
371 }
372
OnDetachFromFrameNode(FrameNode * frameNode)373 void NavDestinationPattern::OnDetachFromFrameNode(FrameNode* frameNode)
374 {
375 CHECK_NULL_VOID(frameNode);
376 auto id = frameNode->GetId();
377 auto pipeline = frameNode->GetContext();
378 CHECK_NULL_VOID(pipeline);
379 pipeline->RemoveWindowStateChangedCallback(id);
380 pipeline->RemoveWindowSizeChangeCallback(id);
381 pipeline->GetMemoryManager()->RemoveRecyclePageNode(id);
382 }
383
DumpInfo()384 void NavDestinationPattern::DumpInfo()
385 {
386 DumpLog::GetInstance().AddDesc(std::string("name: ").append(name_));
387 }
388
OverlayOnBackPressed()389 bool NavDestinationPattern::OverlayOnBackPressed()
390 {
391 CHECK_NULL_RETURN(overlayManager_, false);
392 if (overlayManager_->IsCurrentNodeProcessRemoveOverlay(GetHost(), false)) {
393 return overlayManager_->RemoveOverlay(true);
394 }
395 return false;
396 }
397
NeedIgnoreKeyboard()398 bool NavDestinationPattern::NeedIgnoreKeyboard()
399 {
400 auto layoutProperty = GetLayoutProperty<NavDestinationLayoutProperty>();
401 CHECK_NULL_RETURN(layoutProperty, false);
402 auto& opts = layoutProperty->GetSafeAreaExpandOpts();
403 if (opts && (opts->type & SAFE_AREA_TYPE_KEYBOARD) && (opts->edges & SAFE_AREA_EDGE_BOTTOM)) {
404 return true;
405 }
406 return false;
407 }
408
OnFontScaleConfigurationUpdate()409 void NavDestinationPattern::OnFontScaleConfigurationUpdate()
410 {
411 auto hostNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
412 CHECK_NULL_VOID(hostNode);
413 auto pipeline = hostNode->GetContext();
414 CHECK_NULL_VOID(pipeline);
415 auto titleBarUINode = hostNode->GetTitleBarNode();
416 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(titleBarUINode);
417 CHECK_NULL_VOID(titleBarNode);
418 auto backButtonNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetBackButton());
419 CHECK_NULL_VOID(backButtonNode);
420 if (LessNotEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
421 auto gestureHub = backButtonNode->GetOrCreateGestureEventHub();
422 CHECK_NULL_VOID(gestureHub);
423 gestureHub->SetLongPressEvent(nullptr);
424 auto longPressRecognizer = gestureHub->GetLongPressRecognizer();
425 CHECK_NULL_VOID(longPressRecognizer);
426 longPressRecognizer->SetOnActionEnd(nullptr);
427 return;
428 }
429 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
430 CHECK_NULL_VOID(titleBarPattern);
431 titleBarPattern->InitBackButtonLongPressEvent(backButtonNode);
432 }
433
SetSystemBarStyle(const RefPtr<SystemBarStyle> & style)434 void NavDestinationPattern::SetSystemBarStyle(const RefPtr<SystemBarStyle>& style)
435 {
436 auto host = GetHost();
437 CHECK_NULL_VOID(host);
438 auto pipeline = host->GetContext();
439 CHECK_NULL_VOID(pipeline);
440 auto windowManager = pipeline->GetWindowManager();
441 CHECK_NULL_VOID(windowManager);
442 if (!backupStyle_.has_value()) {
443 backupStyle_ = windowManager->GetSystemBarStyle();
444 }
445 currStyle_ = style;
446 auto navigationNode = AceType::DynamicCast<NavigationGroupNode>(navigationNode_.Upgrade());
447 CHECK_NULL_VOID(navigationNode);
448 auto navigationPattern = navigationNode->GetPattern<NavigationPattern>();
449 if (navigationPattern->IsFullPageNavigation() && navigationPattern->IsTopNavDestination(host)) {
450 if (currStyle_.value() != nullptr) {
451 windowManager->SetSystemBarStyle(currStyle_.value());
452 } else {
453 navigationPattern->TryRestoreSystemBarStyle(windowManager);
454 }
455 }
456 }
457
GetTitlebarZIndex() const458 int32_t NavDestinationPattern::GetTitlebarZIndex() const
459 {
460 return DEFAULT_TITLEBAR_ZINDEX;
461 }
462
OnWindowHide()463 void NavDestinationPattern::OnWindowHide()
464 {
465 CHECK_NULL_VOID(navDestinationContext_);
466 auto navPathInfo = navDestinationContext_->GetNavPathInfo();
467 CHECK_NULL_VOID(navPathInfo);
468 if (!navPathInfo->GetIsEntry()) {
469 return;
470 }
471 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "window lifecycle change to hide, clear navDestination entry tag");
472 navPathInfo->SetIsEntry(false);
473 auto stack = GetNavigationStack().Upgrade();
474 CHECK_NULL_VOID(stack);
475 auto index = navDestinationContext_->GetIndex();
476 stack->SetIsEntryByIndex(index, false);
477 }
478
DumpInfo(std::unique_ptr<JsonValue> & json)479 void NavDestinationPattern::DumpInfo(std::unique_ptr<JsonValue>& json)
480 {
481 json->Put("name", name_.c_str());
482 }
483
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)484 void NavDestinationPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
485 {
486 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
487 CHECK_NULL_VOID(navDestinationGroupNode);
488 if (preWidth_.has_value() && preWidth_.value() != width) {
489 AbortBarAnimation();
490 }
491 preWidth_ = width;
492 // change menu num in landscape and orientation
493 do {
494 if (navDestinationGroupNode->GetPrevMenuIsCustomValue(false)) {
495 break;
496 }
497 auto targetNum = SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE ? MAX_MENU_NUM_LARGE
498 : MAX_MENU_NUM_SMALL;
499 if (targetNum == maxMenuNums_) {
500 break;
501 }
502 maxMenuNums_ = targetNum;
503 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationGroupNode->GetTitleBarNode());
504 CHECK_NULL_VOID(titleBarNode);
505 BuildMenu(navDestinationGroupNode, titleBarNode);
506 titleBarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
507 } while (0);
508 if (type == WindowSizeChangeReason::ROTATION) {
509 CloseLongPressDialog();
510 }
511 }
512
CloseLongPressDialog()513 void NavDestinationPattern::CloseLongPressDialog()
514 {
515 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
516 CHECK_NULL_VOID(navDestinationGroupNode);
517 auto pipeline = navDestinationGroupNode->GetContext();
518 CHECK_NULL_VOID(pipeline);
519 auto overlayManager = pipeline->GetOverlayManager();
520 CHECK_NULL_VOID(overlayManager);
521
522 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(navDestinationGroupNode->GetTitleBarNode());
523 CHECK_NULL_VOID(titleBarNode);
524 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
525 CHECK_NULL_VOID(titleBarPattern);
526 auto backButtonDialogNode = titleBarPattern->GetBackButtonDialogNode();
527 if (backButtonDialogNode) {
528 overlayManager->CloseDialog(backButtonDialogNode);
529 titleBarPattern->SetBackButtonDialogNode(nullptr);
530 }
531 auto menuItemDialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
532 if (menuItemDialogNode) {
533 overlayManager->CloseDialog(menuItemDialogNode);
534 titleBarPattern->SetLargeFontPopUpDialogNode(nullptr);
535 }
536 }
537
UpdateTitleAndToolBarHiddenOffset(float offset)538 void NavDestinationPattern::UpdateTitleAndToolBarHiddenOffset(float offset)
539 {
540 CancelShowTitleAndToolBarTask();
541 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
542 CHECK_NULL_VOID(nodeBase);
543 if (EnableTitleBarSwipe(nodeBase)) {
544 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
545 UpdateBarHiddenOffset(nodeBase, titleBarNode, offset, true);
546 }
547 if (EnableToolBarSwipe(nodeBase)) {
548 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
549 UpdateBarHiddenOffset(nodeBase, toolBarNode, offset, false);
550 }
551 }
552
CancelShowTitleAndToolBarTask()553 void NavDestinationPattern::CancelShowTitleAndToolBarTask()
554 {
555 if (titleBarSwipeContext_.showBarTask) {
556 titleBarSwipeContext_.showBarTask.Cancel();
557 titleBarSwipeContext_.showBarTask.Reset(nullptr);
558 }
559 if (toolBarSwipeContext_.showBarTask) {
560 toolBarSwipeContext_.showBarTask.Cancel();
561 toolBarSwipeContext_.showBarTask.Reset(nullptr);
562 }
563 }
564
ResetTitleAndToolBarState()565 void NavDestinationPattern::ResetTitleAndToolBarState()
566 {
567 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
568 CHECK_NULL_VOID(nodeBase);
569 if (EnableTitleBarSwipe(nodeBase)) {
570 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
571 ResetBarState(nodeBase, titleBarNode, true);
572 }
573 if (EnableToolBarSwipe(nodeBase)) {
574 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
575 ResetBarState(nodeBase, toolBarNode, false);
576 }
577 }
578
ResetBarState(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,bool isTitle)579 void NavDestinationPattern::ResetBarState(const RefPtr<NavDestinationNodeBase>& nodeBase,
580 const RefPtr<FrameNode>& barNode, bool isTitle)
581 {
582 CHECK_NULL_VOID(nodeBase);
583 CHECK_NULL_VOID(barNode);
584 auto& ctx = GetSwipeContext(isTitle);
585 if (ctx.isBarHiding || ctx.isBarShowing) {
586 return;
587 }
588
589 float translate = 0.0f;
590 float barHeight = 0.0f;
591 if (!GetTitleOrToolBarTranslateAndHeight(barNode, translate, barHeight) || NearZero(barHeight)) {
592 return;
593 }
594
595 auto threshold = Dimension(TRANSLATE_THRESHOLD, DimensionUnit::VP).ConvertToPx();
596 float halfBarHeight = barHeight / 2.0f;
597 if (GreatOrEqual(threshold, halfBarHeight)) {
598 threshold = halfBarHeight;
599 }
600 float showAreaHeight = barHeight - std::abs(translate);
601 if (GreatNotEqual(showAreaHeight, 0.0f) && LessNotEqual(showAreaHeight, threshold)) {
602 /**
603 * Scroll to show a small portion of the titleBar&toolBar,
604 * but the height of shownArea is less than the threshold,
605 * it needs to be restored to the hidden state.
606 */
607 StartHideOrShowBarInner(nodeBase, barHeight, translate, isTitle, true);
608 } else if (GreatOrEqual(showAreaHeight, barHeight - threshold) && LessNotEqual(showAreaHeight, barHeight)) {
609 /**
610 * Scroll to hide a small portion of the titleBar&toolBar,
611 * but the height of hiddenArea is less than the threshold,
612 * it needs to be restored to the shown state.
613 */
614 StartHideOrShowBarInner(nodeBase, barHeight, translate, isTitle, false);
615 }
616 }
617
EnableTitleBarSwipe(const RefPtr<NavDestinationNodeBase> & nodeBase)618 bool NavDestinationPattern::EnableTitleBarSwipe(const RefPtr<NavDestinationNodeBase>& nodeBase)
619 {
620 CHECK_NULL_RETURN(nodeBase, false);
621 auto property = nodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
622 CHECK_NULL_RETURN(property, false);
623 return !property->GetHideTitleBarValue(false);
624 }
625
EnableToolBarSwipe(const RefPtr<NavDestinationNodeBase> & nodeBase)626 bool NavDestinationPattern::EnableToolBarSwipe(const RefPtr<NavDestinationNodeBase>& nodeBase)
627 {
628 CHECK_NULL_RETURN(nodeBase, false);
629 auto property = nodeBase->GetLayoutProperty<NavDestinationLayoutPropertyBase>();
630 CHECK_NULL_RETURN(property, false);
631 return !property->GetHideToolBarValue(false);
632 }
633
UpdateBarHiddenOffset(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,float offset,bool isTitle)634 void NavDestinationPattern::UpdateBarHiddenOffset(
635 const RefPtr<NavDestinationNodeBase>& nodeBase, const RefPtr<FrameNode>& barNode, float offset, bool isTitle)
636 {
637 CHECK_NULL_VOID(nodeBase);
638 CHECK_NULL_VOID(barNode);
639 auto& ctx = GetSwipeContext(isTitle);
640 if (ctx.isBarShowing || ctx.isBarHiding) {
641 return;
642 }
643
644 float preTranslate = 0.0f;
645 float barHeight = 0.0f;
646 if (!GetTitleOrToolBarTranslateAndHeight(barNode, preTranslate, barHeight) || NearZero(barHeight)) {
647 return;
648 }
649
650 float newTranslate = 0.0f;
651 if (isTitle) {
652 newTranslate = std::clamp(preTranslate - offset, -barHeight, 0.0f);
653 } else {
654 newTranslate = std::clamp(preTranslate + offset, 0.0f, barHeight);
655 }
656 NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, newTranslate, isTitle);
657
658 auto threshold = Dimension(TRANSLATE_THRESHOLD, DimensionUnit::VP).ConvertToPx();
659 float halfBarHeight = barHeight / 2.0f;
660 if (GreatOrEqual(threshold, halfBarHeight)) {
661 threshold = halfBarHeight;
662 }
663 if (Positive(offset) && LessNotEqual(std::abs(preTranslate), threshold) &&
664 GreatOrEqual(std::abs(newTranslate), threshold)) {
665 // When the scrolling up distance exceeds the threshold, it is necessary to start the hide animation.
666 StartHideOrShowBarInner(nodeBase, barHeight, newTranslate, isTitle, true);
667 } else if (Negative(offset) && LessNotEqual(barHeight - std::abs(preTranslate), threshold) &&
668 GreatOrEqual(barHeight - std::abs(newTranslate), threshold)) {
669 // When the scrolling down distance exceeds the threshold, it is necessary to start the show animation.
670 StartHideOrShowBarInner(nodeBase, barHeight, newTranslate, isTitle, false);
671 }
672 }
673
ShowTitleAndToolBar()674 void NavDestinationPattern::ShowTitleAndToolBar()
675 {
676 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(GetHost());
677 CHECK_NULL_VOID(nodeBase);
678 if (EnableTitleBarSwipe(nodeBase)) {
679 auto titleBarNode = AceType::DynamicCast<TitleBarNode>(nodeBase->GetTitleBarNode());
680 float translate = 0.0f;
681 float barHeight = 0.0f;
682 if (GetTitleOrToolBarTranslateAndHeight(titleBarNode, translate, barHeight)) {
683 if (titleBarSwipeContext_.showBarTask) {
684 titleBarSwipeContext_.showBarTask.Cancel();
685 titleBarSwipeContext_.showBarTask.Reset(nullptr);
686 }
687 StopHideBarIfNeeded(translate, true);
688 StartHideOrShowBarInner(nodeBase, barHeight, translate, true, false);
689 }
690 }
691 if (EnableToolBarSwipe(nodeBase)) {
692 auto toolBarNode = AceType::DynamicCast<NavToolbarNode>(nodeBase->GetToolBarNode());
693 float translate = 0.0f;
694 float barHeight = 0.0f;
695 if (GetTitleOrToolBarTranslateAndHeight(toolBarNode, translate, barHeight)) {
696 if (toolBarSwipeContext_.showBarTask) {
697 toolBarSwipeContext_.showBarTask.Cancel();
698 toolBarSwipeContext_.showBarTask.Reset(nullptr);
699 }
700 StopHideBarIfNeeded(translate, false);
701 StartHideOrShowBarInner(nodeBase, barHeight, translate, false, false);
702 }
703 }
704 }
705
StartHideOrShowBarInner(const RefPtr<NavDestinationNodeBase> & nodeBase,float barHeight,float curTranslate,bool isTitle,bool isHide)706 void NavDestinationPattern::StartHideOrShowBarInner(
707 const RefPtr<NavDestinationNodeBase>& nodeBase, float barHeight, float curTranslate, bool isTitle, bool isHide)
708 {
709 CHECK_NULL_VOID(nodeBase);
710 auto barNode = GetBarNode(nodeBase, isTitle);
711 CHECK_NULL_VOID(barNode);
712
713 auto propertyCallback = [weak = WeakClaim(this), barHeight, isTitle, isHide]() {
714 auto pattern = weak.Upgrade();
715 CHECK_NULL_VOID(pattern);
716 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
717 CHECK_NULL_VOID(nodeBase);
718 auto barNode = pattern->GetBarNode(nodeBase, isTitle);
719 CHECK_NULL_VOID(barNode);
720 float translate = isHide ? (isTitle ? -barHeight : barHeight) : 0.0f;
721 NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, translate, isTitle);
722 };
723 auto finishCallback = [weak = WeakClaim(this), isTitle, isHide]() {
724 auto pattern = weak.Upgrade();
725 CHECK_NULL_VOID(pattern);
726 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
727 CHECK_NULL_VOID(nodeBase);
728 auto barNode = pattern->GetBarNode(nodeBase, isTitle);
729 CHECK_NULL_VOID(barNode);
730 auto& ctx = pattern->GetSwipeContext(isTitle);
731 if (isHide) {
732 ctx.isBarHiding = false;
733 } else {
734 ctx.isBarShowing = false;
735 }
736 };
737 AnimationOption option;
738 option.SetCurve(TRANSLATE_CURVE);
739 auto& ctx = GetSwipeContext(isTitle);
740 if (isHide) {
741 ctx.isBarHiding = true;
742 } else {
743 ctx.isBarShowing = true;
744 }
745 NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, curTranslate, isTitle);
746 AnimationUtils::Animate(option, propertyCallback, finishCallback);
747 }
748
StopHideBarIfNeeded(float curTranslate,bool isTitle)749 void NavDestinationPattern::StopHideBarIfNeeded(float curTranslate, bool isTitle)
750 {
751 auto& ctx = GetSwipeContext(isTitle);
752 if (!ctx.isBarHiding) {
753 return;
754 }
755
756 auto propertyCallback = [weak = WeakClaim(this), isTitle, curTranslate]() {
757 auto pattern = weak.Upgrade();
758 CHECK_NULL_VOID(pattern);
759 auto nodeBase = AceType::DynamicCast<NavDestinationNodeBase>(pattern->GetHost());
760 CHECK_NULL_VOID(nodeBase);
761 auto barNode = pattern->GetBarNode(nodeBase, isTitle);
762 CHECK_NULL_VOID(barNode);
763 NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(nodeBase, barNode, curTranslate, isTitle);
764 };
765 AnimationOption option;
766 option.SetDuration(0);
767 option.SetCurve(Curves::LINEAR);
768 AnimationUtils::Animate(option, propertyCallback);
769 ctx.isBarHiding = false;
770 }
771
GetBarNode(const RefPtr<NavDestinationNodeBase> & nodeBase,bool isTitle)772 RefPtr<FrameNode> NavDestinationPattern::GetBarNode(const RefPtr<NavDestinationNodeBase>& nodeBase, bool isTitle)
773 {
774 CHECK_NULL_RETURN(nodeBase, nullptr);
775 return isTitle ? AceType::DynamicCast<FrameNode>(nodeBase->GetTitleBarNode())
776 : AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarNode());
777 }
778
OnCoordScrollStart()779 void NavDestinationPattern::OnCoordScrollStart()
780 {
781 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
782 CHECK_NULL_VOID(navDestinationGroupNode);
783 auto navDestinationEventHub = navDestinationGroupNode->GetEventHub<NavDestinationEventHub>();
784 CHECK_NULL_VOID(navDestinationEventHub);
785 navDestinationEventHub->FireOnCoordScrollStartAction();
786 }
787
OnCoordScrollUpdate(float offset,float currentOffset)788 float NavDestinationPattern::OnCoordScrollUpdate(float offset, float currentOffset)
789 {
790 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
791 CHECK_NULL_RETURN(navDestinationGroupNode, 0.0f);
792 auto navDestinationEventHub = navDestinationGroupNode->GetEventHub<NavDestinationEventHub>();
793 CHECK_NULL_RETURN(navDestinationEventHub, 0.0f);
794 navDestinationEventHub->FireOnCoordScrollUpdateAction(currentOffset);
795 return 0.0f;
796 }
797
OnCoordScrollEnd()798 void NavDestinationPattern::OnCoordScrollEnd()
799 {
800 auto navDestinationGroupNode = AceType::DynamicCast<NavDestinationGroupNode>(GetHost());
801 CHECK_NULL_VOID(navDestinationGroupNode);
802 auto navDestinationEventHub = navDestinationGroupNode->GetEventHub<NavDestinationEventHub>();
803 CHECK_NULL_VOID(navDestinationEventHub);
804 navDestinationEventHub->FireOnCoordScrollEndAction();
805 }
806 } // namespace OHOS::Ace::NG
807