1 /*
2 * Copyright (c) 2023 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/overlay/sheet_presentation_pattern.h"
17
18 #include "sheet_presentation_property.h"
19
20 #include "base/geometry/dimension.h"
21 #include "base/log/dump_log.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/utils.h"
24 #include "base/window/foldable_window.h"
25 #include "core/animation/animation_pub.h"
26 #include "core/animation/curve.h"
27 #include "core/common/container.h"
28 #include "core/components/drag_bar/drag_bar_theme.h"
29 #include "core/components_ng/base/frame_node.h"
30 #include "core/components_ng/event/event_hub.h"
31 #include "core/components_ng/event/gesture_event_hub.h"
32 #include "core/components_ng/event/touch_event.h"
33 #include "core/components_ng/pattern/image/image_pattern.h"
34 #include "core/components_ng/pattern/navrouter/navdestination_pattern.h"
35 #include "core/components_ng/pattern/overlay/overlay_manager.h"
36 #include "core/components_ng/pattern/overlay/sheet_drag_bar_pattern.h"
37 #include "core/components_ng/pattern/overlay/sheet_manager.h"
38 #include "core/components_ng/pattern/overlay/sheet_style.h"
39 #include "core/components_ng/pattern/scroll/scroll_layout_algorithm.h"
40 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
41 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
42 #include "core/components_ng/pattern/stage/page_pattern.h"
43 #include "core/components_ng/pattern/text/text_layout_property.h"
44 #include "core/components_ng/pattern/text_field/text_field_manager.h"
45 #ifdef WINDOW_SCENE_SUPPORTED
46 #include "core/components_ng/pattern/window_scene/scene/system_window_scene.h"
47 #endif
48 #include "core/components_ng/property/property.h"
49 #include "core/components_v2/inspector/inspector_constants.h"
50 #include "core/event/touch_event.h"
51 #include "core/pipeline_ng/pipeline_context.h"
52
53 namespace OHOS::Ace::NG {
54 namespace {
55 constexpr float SHEET_VISIABLE_ALPHA = 1.0f;
56 constexpr float SHEET_INVISIABLE_ALPHA = 0.0f;
57 constexpr int32_t SHEET_ENTRY_ANIMATION_DURATION = 250;
58 constexpr int32_t SHEET_EXIT_ANIMATION_DURATION = 100;
59 constexpr float SHEET_INVISIABLE_OFFSET = 8.0;
60 constexpr int32_t SHEET_HALF_HEIGHT = 2;
61 constexpr Dimension ARROW_VERTICAL_P1_OFFSET_X = 8.0_vp;
62 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_X = 1.5_vp;
63 constexpr Dimension ARROW_VERTICAL_P2_OFFSET_Y = 7.32_vp;
64 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_X = 1.5_vp;
65 constexpr Dimension ARROW_VERTICAL_P4_OFFSET_Y = 7.32_vp;
66 constexpr Dimension ARROW_VERTICAL_P5_OFFSET_X = 8.0_vp;
67 constexpr Dimension ARROW_RADIUS = 2.0_vp;
68 } // namespace
OnModifyDone()69 void SheetPresentationPattern::OnModifyDone()
70 {
71 auto host = GetHost();
72 CHECK_NULL_VOID(host);
73 auto renderContext = host->GetRenderContext();
74 if (renderContext) {
75 auto pipeline = host->GetContext();
76 CHECK_NULL_VOID(pipeline);
77 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
78 CHECK_NULL_VOID(sheetTheme);
79 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
80 CHECK_NULL_VOID(layoutProperty);
81 auto sheetStyle = layoutProperty->GetSheetStyleValue();
82 BlurStyle blurStyle = static_cast<BlurStyle>(sheetTheme->GetSheetBackgroundBlurStyle());
83 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)
84 && blurStyle != BlurStyle::NO_MATERIAL) {
85 BlurStyleOption options;
86 options.blurStyle = blurStyle;
87 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
88 renderContext->UpdateBackBlurStyle(sheetStyle.backgroundBlurStyle.value_or(options));
89 } else {
90 renderContext->UpdateBackgroundColor(
91 sheetStyle.backgroundColor.value_or(sheetTheme->GetSheetBackgoundColor()));
92 }
93 }
94 InitPanEvent();
95 InitPageHeight();
96 InitScrollProps();
97 InitFoldCreaseRegion();
98 }
99
100 // check device is phone, fold status, and device in landscape
IsPhoneInLandScape()101 bool SheetPresentationPattern::IsPhoneInLandScape()
102 {
103 auto host = GetHost();
104 CHECK_NULL_RETURN(host, false);
105 auto pipelineContext = host->GetContext();
106 CHECK_NULL_RETURN(pipelineContext, false);
107 auto containerId = Container::CurrentId();
108 auto foldWindow = FoldableWindow::CreateFoldableWindow(containerId);
109 CHECK_NULL_RETURN(foldWindow, false);
110 auto sheetTheme = pipelineContext->GetTheme<SheetTheme>();
111 CHECK_NULL_RETURN(sheetTheme, false);
112 auto sheetThemeType = sheetTheme->GetSheetType();
113 if (sheetThemeType == "auto" && !foldWindow->IsFoldExpand() &&
114 SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
115 return true;
116 }
117 return false;
118 }
119
GetSheetTopSafeArea()120 float SheetPresentationPattern::GetSheetTopSafeArea()
121 {
122 auto host = GetHost();
123 CHECK_NULL_RETURN(host, 0.0f);
124 auto pipelineContext = host->GetContext();
125 CHECK_NULL_RETURN(pipelineContext, 0.0f);
126 auto safeAreaInsets = pipelineContext->GetSafeAreaWithoutProcess();
127 auto sheetTopSafeArea = safeAreaInsets.top_.Length();
128 auto windowManager = pipelineContext->GetWindowManager();
129 auto sheetType = GetSheetType();
130 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
131 double deviceHeight = static_cast<double>(SystemProperties::GetDeviceHeight());
132
133 // full screen subwindow sheet is also WINDOW_MODE_FLOATING, can not enter
134 if (windowManager && windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING &&
135 !NearEqual(windowGlobalRect.Height(), deviceHeight)) {
136 sheetTopSafeArea = SHEET_BLANK_FLOATING_STATUS_BAR.ConvertToPx();
137 } else if (sheetType == SheetType::SHEET_BOTTOMLANDSPACE &&
138 AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
139 sheetTopSafeArea = 0.0f;
140 }
141 return sheetTopSafeArea;
142 }
143
InitPageHeight()144 void SheetPresentationPattern::InitPageHeight()
145 {
146 auto pipelineContext = PipelineContext::GetCurrentContext();
147 CHECK_NULL_VOID(pipelineContext);
148 auto safeAreaInsets = pipelineContext->GetSafeAreaWithoutProcess();
149 auto currentTopSafeArea = sheetTopSafeArea_;
150 TAG_LOGD(AceLogTag::ACE_SHEET, "statusBarHeight of sheet by GetSafeAreaWithoutProcess : %{public}u",
151 safeAreaInsets.top_.Length());
152 sheetTopSafeArea_ =
153 GetSheetType() != SheetType::SHEET_BOTTOMLANDSPACE ? safeAreaInsets.top_.Length() : .0f;
154 auto showInPage =
155 GetLayoutProperty<SheetPresentationProperty>()->GetSheetStyleValue(SheetStyle()).showInPage.value_or(false);
156 auto overlay = GetOverlayManager();
157 if (overlay && overlay->IsRootExpansive() && showInPage) {
158 sheetTopSafeArea_ = .0f;
159 }
160
161 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
162 CHECK_NULL_VOID(layoutProperty);
163 auto sheetStyle = layoutProperty->GetSheetStyleValue();
164 if (sheetStyle.sheetType.has_value() && sheetStyle.sheetType.value() == SheetType::SHEET_BOTTOM &&
165 IsPhoneInLandScape()) {
166 sheetTopSafeArea_ = 0.0f;
167 }
168 auto windowManager = pipelineContext->GetWindowManager();
169 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
170 double deviceHeight = static_cast<double>(SystemProperties::GetDeviceHeight());
171 if (windowManager && windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING &&
172 !NearEqual(windowGlobalRect.Height(), deviceHeight)) {
173 sheetTopSafeArea_ = SHEET_BLANK_FLOATING_STATUS_BAR.ConvertToPx();
174 }
175 TAG_LOGD(AceLogTag::ACE_SHEET, "sheetTopSafeArea of sheet is : %{public}f", sheetTopSafeArea_);
176 if (!NearEqual(currentTopSafeArea, sheetTopSafeArea_)) {
177 topSafeAreaChanged_ = true;
178 }
179 auto sheetTheme = pipelineContext->GetTheme<SheetTheme>();
180 CHECK_NULL_VOID(sheetTheme);
181 sheetThemeType_ = sheetTheme->GetSheetType();
182 InitSheetMode();
183 }
184
InitScrollProps()185 void SheetPresentationPattern::InitScrollProps()
186 {
187 auto host = GetHost();
188 CHECK_NULL_VOID(host);
189 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
190 CHECK_NULL_VOID(scrollNode);
191 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
192 CHECK_NULL_VOID(scrollPattern);
193
194 // When sheet content height is larger than sheet height,
195 // the sheet height should set scroll always enabled.
196 scrollPattern->SetAlwaysEnabled(scrollSizeMode_ == ScrollSizeMode::CONTINUOUS && IsScrollable());
197 }
198
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)199 bool SheetPresentationPattern::OnDirtyLayoutWrapperSwap(
200 const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
201 {
202 if (config.skipMeasure && config.skipLayout) {
203 return false;
204 }
205 auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
206 CHECK_NULL_RETURN(layoutAlgorithmWrapper, false);
207 auto sheetLayoutAlgorithm =
208 DynamicCast<SheetPresentationLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
209 CHECK_NULL_RETURN(sheetLayoutAlgorithm, false);
210 InitPageHeight();
211 if (sheetLayoutAlgorithm->GetSheetMaxHeight() > 0) {
212 pageHeight_ = sheetLayoutAlgorithm->GetSheetMaxHeight();
213 sheetMaxHeight_ = sheetLayoutAlgorithm->GetSheetMaxHeight() - sheetTopSafeArea_;
214 sheetMaxWidth_ = sheetLayoutAlgorithm->GetSheetMaxWidth();
215 centerHeight_ = sheetLayoutAlgorithm->GetCenterHeight();
216 if (!NearEqual(sheetOffsetX_, sheetLayoutAlgorithm->GetSheetOffsetX()) ||
217 !NearEqual(sheetOffsetY_, sheetLayoutAlgorithm->GetSheetOffsetY())) {
218 sheetOffsetX_ = sheetLayoutAlgorithm->GetSheetOffsetX();
219 sheetOffsetY_ = sheetLayoutAlgorithm->GetSheetOffsetY();
220 arrowOffset_ = OffsetF(sheetLayoutAlgorithm->GetArrowOffsetX(), .0f);
221 windowChanged_ = true;
222 }
223 }
224 InitialLayoutProps();
225 UpdateFontScaleStatus();
226 UpdateDragBarStatus();
227 UpdateCloseIconStatus();
228 UpdateTitlePadding();
229 UpdateSheetTitle();
230 ClipSheetNode();
231 CheckBuilderChange();
232 if (GetSheetType() != SheetType::SHEET_POPUP) {
233 if (windowRotate_) {
234 // When rotating the screen,
235 // first switch the sheet to the position corresponding to the proportion before rotation
236 TranslateTo(pageHeight_ - height_);
237 windowRotate_ = false;
238 } else {
239 // After rotation, if need to avoid the keyboard, trigger the avoidance behavior
240 AvoidSafeArea();
241 }
242 }
243 if (GetSheetType() == SheetType::SHEET_POPUP) {
244 MarkSheetPageNeedRender();
245 }
246 return true;
247 }
248
CheckBuilderChange()249 void SheetPresentationPattern::CheckBuilderChange()
250 {
251 auto host = GetHost();
252 CHECK_NULL_VOID(host);
253 auto builderNode = GetFirstFrameNodeOfBuilder();
254 CHECK_NULL_VOID(builderNode);
255 auto eventHub = builderNode->GetEventHub<EventHub>();
256 CHECK_NULL_VOID(eventHub);
257 OnAreaChangedFunc onBuilderAreaChangedFunc = [sheetNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
258 const OffsetF& /* oldOrigin */, const RectF& /* rect */,
259 const OffsetF& /* origin */) {
260 auto sheetNode = sheetNodeWk.Upgrade();
261 CHECK_NULL_VOID(sheetNode);
262 auto sheetPattern = sheetNode->GetPattern<SheetPresentationPattern>();
263 CHECK_NULL_VOID(sheetPattern);
264 auto layoutProperty = sheetNode->GetLayoutProperty<SheetPresentationProperty>();
265 CHECK_NULL_VOID(layoutProperty);
266 auto sheetStyle = layoutProperty->GetSheetStyleValue();
267 if (sheetStyle.sheetHeight.sheetMode == SheetMode::AUTO) {
268 sheetNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
269 }
270 };
271 eventHub->AddInnerOnAreaChangedCallback(builderNode->GetId(), std::move(onBuilderAreaChangedFunc));
272 }
273
AvoidAiBar()274 void SheetPresentationPattern::AvoidAiBar()
275 {
276 CHECK_NULL_VOID(Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN));
277 if (!IsTypeNeedAvoidAiBar()) {
278 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet need not avoid AiBar.");
279 return;
280 }
281 auto host = GetHost();
282 CHECK_NULL_VOID(host);
283 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
284 CHECK_NULL_VOID(scrollNode);
285 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
286 CHECK_NULL_VOID(scrollPattern);
287 if (NonPositive(scrollPattern->GetScrollableDistance()) || isScrolling_) {
288 return;
289 }
290 auto pipeline = PipelineContext::GetCurrentContext();
291 CHECK_NULL_VOID(pipeline);
292 auto inset = pipeline->GetSafeArea();
293 auto layoutProperty = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
294 layoutProperty->UpdateScrollContentEndOffset(inset.bottom_.Length());
295 TAG_LOGD(AceLogTag::ACE_SHEET, "AvoidAiBar function execution completed");
296 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
297 }
298
IsScrollable() const299 bool SheetPresentationPattern::IsScrollable() const
300 {
301 auto host = GetHost();
302 CHECK_NULL_RETURN(host, false);
303 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
304 CHECK_NULL_RETURN(scrollNode, false);
305 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
306 CHECK_NULL_RETURN(scrollPattern, false);
307 return Positive(scrollPattern->GetScrollableDistance());
308 }
309
OnAttachToFrameNode()310 void SheetPresentationPattern::OnAttachToFrameNode()
311 {
312 auto host = GetHost();
313 CHECK_NULL_VOID(host);
314 auto pipelineContext = host->GetContext();
315 CHECK_NULL_VOID(pipelineContext);
316 scale_ = pipelineContext->GetFontScale();
317 InitFoldState();
318 pipelineContext->AddWindowSizeChangeCallback(host->GetId());
319 host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
320 host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
321 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetId_);
322 CHECK_NULL_VOID(targetNode);
323 pipelineContext->AddOnAreaChangeNode(targetNode->GetId());
324 OnAreaChangedFunc onAreaChangedFunc = [sheetNodeWk = WeakPtr<FrameNode>(host)](const RectF& /* oldRect */,
325 const OffsetF& /* oldOrigin */, const RectF& /* rect */,
326 const OffsetF& /* origin */) {
327 auto sheetNode = sheetNodeWk.Upgrade();
328 CHECK_NULL_VOID(sheetNode);
329 auto sheetPattern = sheetNode->GetPattern<SheetPresentationPattern>();
330 CHECK_NULL_VOID(sheetPattern);
331 if (sheetPattern->GetSheetType() == SheetType::SHEET_POPUP) {
332 sheetNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
333 }
334 };
335 auto eventHub = targetNode->GetEventHub<EventHub>();
336 CHECK_NULL_VOID(eventHub);
337 eventHub->AddInnerOnAreaChangedCallback(host->GetId(), std::move(onAreaChangedFunc));
338
339 auto gesture = host->GetOrCreateGestureEventHub();
340 CHECK_NULL_VOID(gesture);
341 auto touchTask = [](TouchEventInfo& info) {
342 info.SetStopPropagation(true);
343 TAG_LOGD(AceLogTag::ACE_SHEET, "The sheet hits the touch event.");
344 };
345 gesture->AddTouchEvent(MakeRefPtr<TouchEventImpl>(std::move(touchTask)));
346 RegisterHoverModeChangeCallback();
347 }
348
OnDetachFromFrameNode(FrameNode * sheetNode)349 void SheetPresentationPattern::OnDetachFromFrameNode(FrameNode* sheetNode)
350 {
351 CHECK_NULL_VOID(sheetNode);
352 auto pipeline = sheetNode->GetContext();
353 CHECK_NULL_VOID(pipeline);
354 pipeline->RemoveWindowSizeChangeCallback(sheetNode->GetId());
355 auto targetNode = FrameNode::GetFrameNode(targetTag_, targetId_);
356 CHECK_NULL_VOID(targetNode);
357 auto eventHub = targetNode->GetEventHub<EventHub>();
358 CHECK_NULL_VOID(eventHub);
359 eventHub->RemoveInnerOnAreaChangedCallback(sheetNode->GetId());
360 if (HasHoverModeChangedCallbackId()) {
361 pipeline->UnRegisterHalfFoldHoverChangedCallback(hoverModeChangedCallbackId_.value_or(-1));
362 }
363 }
364
RegisterHoverModeChangeCallback()365 void SheetPresentationPattern::RegisterHoverModeChangeCallback()
366 {
367 auto host = GetHost();
368 CHECK_NULL_VOID(host);
369 auto context = host->GetContext();
370 CHECK_NULL_VOID(context);
371 auto hoverModeChangeCallback = [weak = WeakClaim(this)](bool isHalfFoldHover) {
372 auto pattern = weak.Upgrade();
373 CHECK_NULL_VOID(pattern);
374 auto host = pattern->GetHost();
375 CHECK_NULL_VOID(host);
376 auto context = host->GetContext();
377 CHECK_NULL_VOID(context);
378 AnimationOption optionPosition;
379 auto motion = AceType::MakeRefPtr<ResponsiveSpringMotion>(0.35f, 1.0f, 0.0f);
380 optionPosition.SetCurve(motion);
381 context->FlushUITasks();
382 context->Animate(
383 optionPosition, motion,
384 [host, context]() {
385 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
386 context->FlushUITasks();
387 },
388 [weak]() {
389 auto pattern = weak.Upgrade();
390 CHECK_NULL_VOID(pattern);
391 pattern->FireHoverModeChangeCallback();
392 });
393 };
394 auto hoverModeCallId = context->RegisterHalfFoldHoverChangedCallback(std::move(hoverModeChangeCallback));
395 UpdateHoverModeChangedCallbackId(hoverModeCallId);
396 }
397
SetSheetBorderWidth(bool isPartialUpdate)398 void SheetPresentationPattern::SetSheetBorderWidth(bool isPartialUpdate)
399 {
400 auto host = GetHost();
401 CHECK_NULL_VOID(host);
402 auto pipeline = host->GetContext();
403 CHECK_NULL_VOID(pipeline);
404 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
405 CHECK_NULL_VOID(sheetTheme);
406 auto sheetType = GetSheetType();
407 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
408 CHECK_NULL_VOID(layoutProperty);
409 auto sheetStyle = layoutProperty->GetSheetStyleValue();
410 auto renderContext = host->GetRenderContext();
411 CHECK_NULL_VOID(renderContext);
412 renderContext->SetClipToBounds(true);
413 if (sheetStyle.borderWidth.has_value()) {
414 auto sheetRadius = sheetTheme->GetSheetRadius();
415 auto borderWidth = sheetStyle.borderWidth.value();
416 BorderRadiusProperty borderRadius;
417 if ((sheetType == SheetType::SHEET_CENTER) || (sheetType == SheetType::SHEET_POPUP)) {
418 borderRadius.SetRadius(sheetRadius);
419 } else {
420 borderRadius = BorderRadiusProperty(sheetRadius, sheetRadius, 0.0_vp, 0.0_vp);
421 borderWidth.bottomDimen = 0.0_vp;
422 }
423 renderContext->UpdateBorderRadius(borderRadius);
424 layoutProperty->UpdateBorderWidth(borderWidth);
425 renderContext->UpdateBorderWidth(borderWidth);
426 } else if (renderContext->GetBorderWidth().has_value() && !isPartialUpdate) {
427 BorderWidthProperty borderWidth;
428 borderWidth.SetBorderWidth(0.0_vp);
429 layoutProperty->UpdateBorderWidth(borderWidth);
430 renderContext->UpdateBorderWidth(borderWidth);
431 }
432
433 SetSheetOuterBorderWidth(sheetTheme, sheetStyle);
434 }
435
436 // initial drag gesture event
InitPanEvent()437 void SheetPresentationPattern::InitPanEvent()
438 {
439 auto host = GetHost();
440 CHECK_NULL_VOID(host);
441
442 auto hub = host->GetEventHub<EventHub>();
443 CHECK_NULL_VOID(hub);
444 auto gestureHub = hub->GetOrCreateGestureEventHub();
445 CHECK_NULL_VOID(gestureHub);
446 if (panEvent_) {
447 return;
448 }
449
450 auto actionStartTask = [weak = WeakClaim(this)](const GestureEvent& event) {
451 auto pattern = weak.Upgrade();
452 if (pattern) {
453 pattern->HandleDragStart();
454 }
455 };
456
457 auto actionUpdateTask = [weak = WeakClaim(this)](const GestureEvent& info) {
458 auto pattern = weak.Upgrade();
459 if (pattern) {
460 pattern->HandleDragUpdate(info);
461 }
462 };
463
464 auto actionEndTask = [weak = WeakClaim(this)](const GestureEvent& info) {
465 auto pattern = weak.Upgrade();
466 if (pattern) {
467 pattern->HandleDragEnd(info.GetMainVelocity());
468 }
469 };
470 auto actionCancelTask = [weak = WeakClaim(this)]() {
471 auto pattern = weak.Upgrade();
472 if (pattern) {
473 pattern->HandleDragEnd({});
474 }
475 };
476 PanDirection panDirection;
477 panDirection.type = PanDirection::VERTICAL;
478 panEvent_ = MakeRefPtr<PanEvent>(
479 std::move(actionStartTask), std::move(actionUpdateTask), std::move(actionEndTask), std::move(actionCancelTask));
480 gestureHub->AddPanEvent(panEvent_, panDirection, 1, DEFAULT_PAN_DISTANCE);
481 }
482
HandleDragStart()483 void SheetPresentationPattern::HandleDragStart()
484 {
485 InitScrollProps();
486 SetIsDragging(true);
487 if (animation_ && isAnimationProcess_) {
488 AnimationUtils::StopAnimation(animation_);
489 isAnimationBreak_ = true;
490 }
491 currentOffset_ = 0.0f;
492 isDirectionUp_ = true;
493 }
494
HandleDragUpdate(const GestureEvent & info)495 void SheetPresentationPattern::HandleDragUpdate(const GestureEvent& info)
496 {
497 auto sheetType = GetSheetType();
498 if (sheetType == SheetType::SHEET_POPUP) {
499 return;
500 }
501 auto mainDelta = static_cast<float>(info.GetMainDelta());
502 auto host = GetHost();
503 CHECK_NULL_VOID(host);
504 auto tempOffset = currentOffset_;
505 auto detentSize = sheetDetentHeight_.size();
506 if (detentSize <= 0) {
507 return;
508 }
509 auto height = GetSheetHeightBeforeDragUpdate();
510 auto maxDetentSize = GetMaxSheetHeightBeforeDragUpdate();
511 if (GreatNotEqual((height - currentOffset_), maxDetentSize)) {
512 if (LessNotEqual(mainDelta, 0) && GreatNotEqual(sheetMaxHeight_, 0.0f)) {
513 auto friction = CalculateFriction((height - currentOffset_) / sheetMaxHeight_);
514 mainDelta = mainDelta * friction;
515 }
516 }
517 currentOffset_ = currentOffset_ + mainDelta;
518 if (NearEqual(currentOffset_, tempOffset)) {
519 return;
520 }
521 auto pageHeight = GetPageHeightWithoutOffset();
522 auto offset = pageHeight - height + currentOffset_;
523 if (LessOrEqual(offset, (pageHeight - sheetMaxHeight_))) {
524 offset = pageHeight - sheetMaxHeight_;
525 currentOffset_ = height - sheetMaxHeight_;
526 }
527 bool isNeedChangeScrollHeight = scrollSizeMode_ == ScrollSizeMode::CONTINUOUS && currentOffset_ < 0;
528 if (isNeedChangeScrollHeight) {
529 ChangeScrollHeight(height - currentOffset_);
530 }
531 ProcessColumnRect(height - currentOffset_);
532 auto renderContext = host->GetRenderContext();
533 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
534 if (IsSheetBottomStyle()) {
535 OnHeightDidChange(height_ - currentOffset_ + sheetHeightUp_);
536 }
537 }
538
HandleDragEnd(float dragVelocity)539 void SheetPresentationPattern::HandleDragEnd(float dragVelocity)
540 {
541 isNeedProcessHeight_ = true;
542 SetIsDragging(false);
543 auto sheetDetentsSize = sheetDetentHeight_.size();
544 if ((sheetDetentsSize == 0) || (GetSheetType() == SheetType::SHEET_POPUP)) {
545 return;
546 }
547 float upHeight = 0.0f;
548 float downHeight = 0.0f;
549 auto height = GetSheetHeightBeforeDragUpdate();
550 auto currentSheetHeight =
551 GreatNotEqual((height - currentOffset_), sheetMaxHeight_) ? sheetMaxHeight_ : (height - currentOffset_);
552 start_ = currentSheetHeight;
553 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet HandleDragEnd, current height is: %{public}f", currentSheetHeight);
554
555 // record the drag position
556 uint32_t detentsLowerPos = 0;
557 uint32_t detentsUpperPos = 0;
558 ComputeDetentsPos(currentSheetHeight, upHeight, downHeight, detentsLowerPos, detentsUpperPos);
559
560 // when drag velocity is under the threshold and the sheet height is not in the middle of lower and upper bound.
561 if ((LessNotEqual(std::abs(dragVelocity), SHEET_VELOCITY_THRESHOLD)) &&
562 (!NearEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight)))) {
563 // check whether the lower or upper index is closer to the current height of the sheet page
564 if (GreatNotEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight))) {
565 if (NearZero(downHeight)) {
566 SheetInteractiveDismiss(BindSheetDismissReason::SLIDE_DOWN, std::abs(dragVelocity));
567 } else {
568 detentsIndex_ = detentsLowerPos;
569 ChangeSheetHeight(downHeight);
570 ChangeSheetPage(height);
571 SheetTransition(true, std::abs(dragVelocity));
572 }
573 } else if (LessNotEqual(std::abs(currentSheetHeight - upHeight), std::abs(currentSheetHeight - downHeight))) {
574 detentsIndex_ = detentsUpperPos;
575 ChangeSheetHeight(upHeight);
576 ChangeSheetPage(height);
577 SheetTransition(true, std::abs(dragVelocity));
578 }
579 } else {
580 // when drag velocity is over the threshold
581 if (GreatOrEqual(dragVelocity, 0.0f)) {
582 if (NearZero(downHeight)) {
583 SheetInteractiveDismiss(BindSheetDismissReason::SLIDE_DOWN, std::abs(dragVelocity));
584 } else {
585 detentsIndex_ = detentsLowerPos;
586 ChangeSheetHeight(downHeight);
587 ChangeSheetPage(height);
588 SheetTransition(true, std::abs(dragVelocity));
589 }
590 } else {
591 detentsIndex_ = detentsUpperPos;
592 ChangeSheetHeight(upHeight);
593 ChangeSheetPage(height);
594 SheetTransition(true, std::abs(dragVelocity));
595 }
596 }
597
598 // match the sorted detents index to the unsorted one
599 auto detentHeight = sheetDetentHeight_[detentsIndex_];
600 auto pos = std::find(unSortedSheetDentents_.begin(), unSortedSheetDentents_.end(), detentHeight);
601 if (pos != std::end(unSortedSheetDentents_)) {
602 auto idx = static_cast<uint32_t>(std::distance(unSortedSheetDentents_.begin(), pos));
603 detentsFinalIndex_ = idx;
604 }
605 }
606
ComputeDetentsPos(float currentSheetHeight,float & upHeight,float & downHeight,uint32_t & detentsLowerPos,uint32_t & detentsUpperPos)607 void SheetPresentationPattern::ComputeDetentsPos(
608 float currentSheetHeight, float& upHeight, float& downHeight, uint32_t& detentsLowerPos, uint32_t& detentsUpperPos)
609 {
610 // when drag the sheet page, find the lower and upper index range
611 auto lowerIter = std::lower_bound(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), currentSheetHeight);
612 auto upperIter = std::upper_bound(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), currentSheetHeight);
613 auto sheetDetentsSize = sheetDetentHeight_.size();
614 if (sheetDetentsSize <= 0) {
615 TAG_LOGI(AceLogTag::ACE_SHEET, "SheetDetentsSize is less than or equal to 0");
616 return;
617 }
618 if (lowerIter == sheetDetentHeight_.end() || upperIter == sheetDetentHeight_.end()) {
619 // when drag over the highest sheet page
620 upHeight = sheetDetentHeight_[sheetDetentsSize - 1];
621 downHeight = sheetDetentHeight_[sheetDetentsSize - 1];
622 detentsLowerPos = sheetDetentsSize - 1;
623 detentsUpperPos = sheetDetentsSize - 1;
624 } else {
625 auto lowerPosition = static_cast<uint32_t>(std::distance(sheetDetentHeight_.begin(), lowerIter));
626 auto upperPosition = static_cast<uint32_t>(std::distance(sheetDetentHeight_.begin(), upperIter));
627 if (lowerPosition == 0) {
628 upHeight = sheetDetentHeight_[lowerPosition];
629 downHeight = 0;
630 } else {
631 // the first largest height greater than the currentsheet height
632 upHeight = sheetDetentHeight_[upperPosition];
633
634 // the largest height lower than the currentsheet height
635 downHeight = sheetDetentHeight_[lowerPosition - 1];
636 detentsLowerPos = lowerPosition - 1;
637 detentsUpperPos = upperPosition;
638 }
639 }
640 }
641
ChangeSheetPage(float height)642 void SheetPresentationPattern::ChangeSheetPage(float height)
643 {
644 if (IsAvoidingKeyboard() && keyboardAvoidMode_ == SheetKeyboardAvoidMode::TRANSLATE_AND_SCROLL) {
645 return;
646 }
647 ChangeScrollHeight(height);
648 ProcessColumnRect(height);
649 }
650
OnCoordScrollStart()651 void SheetPresentationPattern::OnCoordScrollStart()
652 {
653 if (animation_ && isAnimationProcess_) {
654 AnimationUtils::StopAnimation(animation_);
655 isAnimationBreak_ = true;
656 }
657 currentOffset_ = 0.0f;
658 }
659
OnCoordScrollUpdate(float scrollOffset)660 bool SheetPresentationPattern::OnCoordScrollUpdate(float scrollOffset)
661 {
662 if (!GetShowState() || !IsScrollable()) {
663 return false;
664 }
665
666 auto sheetType = GetSheetType();
667 auto sheetDetentsSize = sheetDetentHeight_.size();
668 if ((sheetType == SheetType::SHEET_POPUP) || (sheetDetentsSize == 0)) {
669 return false;
670 }
671 auto height = GetSheetHeightBeforeDragUpdate();
672 if ((NearZero(currentOffset_)) && (LessNotEqual(scrollOffset, 0.0f)) &&
673 (GreatOrEqual(height, GetMaxSheetHeightBeforeDragUpdate()))) {
674 return false;
675 }
676 auto host = GetHost();
677 CHECK_NULL_RETURN(host, false);
678 currentOffset_ = currentOffset_ + scrollOffset;
679 auto pageHeight = GetPageHeightWithoutOffset();
680 auto offset = pageHeight - height + currentOffset_;
681 if (LessOrEqual(offset, pageHeight - sheetMaxHeight_)) {
682 offset = pageHeight - sheetMaxHeight_;
683 currentOffset_ = height - sheetMaxHeight_;
684 }
685 ProcessColumnRect(height - currentOffset_);
686 auto renderContext = host->GetRenderContext();
687 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
688 return true;
689 }
690
OnCoordScrollEnd(float dragVelocity)691 void SheetPresentationPattern::OnCoordScrollEnd(float dragVelocity)
692 {
693 HandleDragEnd(dragVelocity);
694 }
695
InitialLayoutProps()696 void SheetPresentationPattern::InitialLayoutProps()
697 {
698 CheckSheetHeightChange();
699 InitSheetDetents();
700 }
701
InitialSingleGearHeight(NG::SheetStyle & sheetStyle)702 float SheetPresentationPattern::InitialSingleGearHeight(NG::SheetStyle& sheetStyle)
703 {
704 auto largeHeight = sheetMaxHeight_ - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
705 float sheetHeight = largeHeight;
706 auto sheetNode = GetHost();
707 CHECK_NULL_RETURN(sheetNode, sheetHeight);
708 if (sheetStyle.sheetHeight.sheetMode.has_value()) {
709 if (sheetStyle.sheetHeight.sheetMode == SheetMode::MEDIUM) {
710 sheetHeight = pageHeight_ * MEDIUM_SIZE;
711 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
712 sheetHeight = pageHeight_ * MEDIUM_SIZE_PRE;
713 }
714 } else if (sheetStyle.sheetHeight.sheetMode == SheetMode::LARGE) {
715 sheetHeight = largeHeight;
716 } else if (sheetStyle.sheetHeight.sheetMode == SheetMode::AUTO) {
717 sheetHeight = GetFitContentHeight();
718 if (sheetHeight > largeHeight) {
719 sheetHeight = largeHeight;
720 }
721 HandleFitContontChange(sheetHeight);
722 }
723 } else {
724 float height = 0.0f;
725 if (sheetStyle.sheetHeight.height->Unit() == DimensionUnit::PERCENT) {
726 height = sheetStyle.sheetHeight.height->ConvertToPxWithSize(sheetMaxHeight_);
727 } else {
728 height = sheetStyle.sheetHeight.height->ConvertToPx();
729 }
730 if (GreatNotEqual(height, largeHeight)) {
731 sheetHeight = largeHeight;
732 } else if (LessNotEqual(height, 0)) {
733 sheetHeight = largeHeight;
734 } else {
735 sheetHeight = height;
736 }
737 }
738 return sheetHeight;
739 }
740
AvoidSafeArea(bool forceAvoid)741 void SheetPresentationPattern::AvoidSafeArea(bool forceAvoid)
742 {
743 auto sheetType = GetSheetType();
744 if (sheetType == SheetType::SHEET_POPUP || IsCurSheetNeedHalfFoldHover()) {
745 return;
746 }
747 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_THIRTEEN)) {
748 AvoidKeyboardBySheetMode(forceAvoid);
749 return;
750 }
751 auto host = GetHost();
752 CHECK_NULL_VOID(host);
753 auto pipelineContext = PipelineContext::GetCurrentContext();
754 CHECK_NULL_VOID(pipelineContext);
755 auto manager = pipelineContext->GetSafeAreaManager();
756 if (!forceAvoid && keyboardHeight_ == manager->GetKeyboardInset().Length()) {
757 return;
758 }
759 keyboardHeight_ = manager->GetKeyboardInset().Length();
760 CHECK_NULL_VOID(host->GetFocusHub());
761 auto heightUp = host->GetFocusHub()->IsCurrentFocus() ? GetSheetHeightChange() : 0.0f;
762 sheetHeightUp_ = heightUp;
763 if (isDismissProcess_) {
764 TAG_LOGD(AceLogTag::ACE_SHEET,
765 "The sheet will disappear, so there's no need to handle canceling keyboard avoidance here.");
766 return;
767 }
768 TAG_LOGD(AceLogTag::ACE_SHEET, "To avoid Keyboard, sheet height increase %{public}f.", heightUp);
769 auto offset = pageHeight_ - height_ - heightUp;
770 auto renderContext = host->GetRenderContext();
771 if (isScrolling_) {
772 // if scrolling and keyboard will down, scroll needs to reset.
773 if (NearZero(heightUp)) {
774 ScrollTo(.0f);
775 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
776 } else {
777 sheetHeightUp_ = pageHeight_ - (SHEET_BLANK_MINI_HEIGHT.ConvertToPx() + sheetTopSafeArea_) - height_;
778 // Otherwise, sheet is necessary to raise and trigger scroll scrolling
779 // sheet is raised to the top first
780 renderContext->UpdateTransformTranslate(
781 { 0.0f, SHEET_BLANK_MINI_HEIGHT.ConvertToPx() + sheetTopSafeArea_, 0.0f });
782 // Then adjust the remaining height(heightUp = h - maxH) difference by scrolling
783 ScrollTo(heightUp);
784 }
785 } else {
786 // offset: translate endpoint, calculated from top
787 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
788 }
789 if (IsSheetBottomStyle()) {
790 OnHeightDidChange(height_ + sheetHeightUp_);
791 }
792 }
793
GetSheetHeightChange()794 float SheetPresentationPattern::GetSheetHeightChange()
795 {
796 // TextFieldManagerNG::GetClickPosition: The upper left corner offset of the cursor position relative to rootNode
797 // TextFieldManagerNG::GetHeight: the cursor Height + 24vp
798 auto pipelineContext = PipelineContext::GetCurrentContext();
799 CHECK_NULL_RETURN(pipelineContext, .0f);
800 auto manager = pipelineContext->GetSafeAreaManager();
801 auto keyboardInsert = manager->GetKeyboardInset();
802 if (keyboardInsert.Length() == 0) {
803 return 0.f;
804 }
805 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipelineContext->GetTextFieldManager());
806 // inputH : Distance from input component's Caret to bottom of screen
807 // = caret's offset + caret's height + 24vp
808 if (textFieldManager && !textFieldManager->GetOptionalClickPosition().has_value() &&
809 !pipelineContext->UsingCaretAvoidMode()) {
810 TAG_LOGD(AceLogTag::ACE_SHEET, "illegal caret position, don't calc height this time");
811 return .0f;
812 }
813 float inputH = 0.f;
814 if (pipelineContext->UsingCaretAvoidMode()) {
815 // when user scroll after avoiding keyboard, we need to update scroll offset before avoid keyboard twice.
816 GetCurrentScrollHeight();
817 // when avoiding keyboard twice, recover input height before avoiding is needed.
818 inputH = textFieldManager ? pipelineContext->GetRootHeight() -
819 textFieldManager->GetFocusedNodeCaretRect().Top() - textFieldManager->GetHeight() - sheetHeightUp_ -
820 scrollHeight_ : 0.f;
821 } else {
822 inputH = textFieldManager ? (pipelineContext->GetRootHeight() - textFieldManager->GetClickPosition().GetY() -
823 textFieldManager->GetHeight()) : 0.f;
824 }
825 // keyboardH : keyboard height + height of the bottom navigation bar
826 auto keyboardH = keyboardInsert.Length() + manager->GetSystemSafeArea().bottom_.Length();
827 // The minimum height of the input component from the bottom of the screen after popping up the soft keyboard
828 auto inputMinH = keyboardH;
829 // the LARGE sheet is 15vp from the status bar, and SHEET_CENTER's Node height not equal to screen height.
830 auto largeHeight = pipelineContext->GetRootHeight() - SHEET_BLANK_MINI_HEIGHT.ConvertToPx() - sheetTopSafeArea_;
831 // maxH : height that the sheet can reach the stage = the LARGE sheet - Current sheet height
832 auto maxH = largeHeight - height_;
833 if (inputH >= inputMinH) {
834 // sheet needs not up
835 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet needs not up");
836 return .0f;
837 }
838 // The expected height of the sheet to be lifted
839 auto h = inputMinH - inputH;
840 if (h <= maxH) {
841 RecoverScrollOrResizeAvoidStatus();
842 // sheet is lifted up with h
843 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet is lifted up with h = %{public}f", h);
844 return h;
845 }
846 // h > maxH, sheet goes up to the LARGE, then adjust the remaining height(h - maxH) difference by scrolling
847 if (IsResizeWhenAvoidKeyboard()) {
848 // remaing height need to update to (keyboardH - bottomDistance) when in resize mode after translate
849 inputH = sheetType_ == SheetType::SHEET_CENTER ? height_ - centerHeight_ : 0.0f;
850 h = inputMinH - inputH;
851 }
852 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet is LARGE, and there is [%{public}f] height left to be processed.", h - maxH);
853 isScrolling_ = true;
854 return h - maxH;
855 }
856
CreatePropertyCallback()857 void SheetPresentationPattern::CreatePropertyCallback()
858 {
859 if (property_) {
860 return;
861 }
862 auto propertyCallback = [weak = AceType::WeakClaim(this)](float position) {
863 auto ref = weak.Upgrade();
864 CHECK_NULL_VOID(ref);
865 ref->OnHeightDidChange(static_cast<int>(position));
866 };
867 property_ = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
868 }
869
ModifyFireSheetTransition(float dragVelocity)870 void SheetPresentationPattern::ModifyFireSheetTransition(float dragVelocity)
871 {
872 TAG_LOGD(AceLogTag::ACE_SHEET, "ModifyFireSheetTransition function enter");
873 auto host = GetHost();
874 CHECK_NULL_VOID(host);
875 auto renderContext = host->GetRenderContext();
876 CHECK_NULL_VOID(renderContext);
877 AnimationOption option;
878 const RefPtr<InterpolatingSpring> curve = AceType::MakeRefPtr<InterpolatingSpring>(
879 dragVelocity / SHEET_VELOCITY_THRESHOLD, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
880 option.SetCurve(curve);
881 option.SetFillMode(FillMode::FORWARDS);
882 auto offset = UpdateSheetTransitionOffset();
883 CreatePropertyCallback();
884 CHECK_NULL_VOID(property_);
885 renderContext->AttachNodeAnimatableProperty(property_);
886 property_->SetPropertyUnit(PropertyUnit::PIXEL_POSITION);
887
888 auto finishCallback = [weak = AceType::WeakClaim(this)]() {
889 auto ref = weak.Upgrade();
890 CHECK_NULL_VOID(ref);
891 if (!ref->GetAnimationBreak()) {
892 ref->SetAnimationProcess(false);
893 ref->ChangeSheetPage(ref->height_);
894 } else {
895 ref->isAnimationBreak_ = false;
896 }
897 ref->AvoidAiBar();
898 ref->isNeedProcessHeight_ = false;
899 ref->FireOnDetentsDidChange(ref->height_);
900 ref->preDidHeight_ = ref->height_;
901 ref->isSpringBack_ = false;
902 };
903
904 isAnimationProcess_ = true;
905
906 property_->Set(start_);
907 animation_ = AnimationUtils::StartAnimation(
908 option,
909 [weak = AceType::WeakClaim(this), renderContext, offset]() {
910 auto ref = weak.Upgrade();
911 CHECK_NULL_VOID(ref);
912 if (renderContext) {
913 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
914 ref->property_->Set(ref->height_ + ref->sheetHeightUp_);
915 bool isNeedChangeScrollHeight =
916 ref->scrollSizeMode_ == ScrollSizeMode::CONTINUOUS && ref->isDirectionUp_;
917 if (isNeedChangeScrollHeight) {
918 ref->ChangeScrollHeight(ref->height_);
919 }
920 }
921 },
922 finishCallback);
923 }
924
925 /**
926 * @brief Get the max height before drag or nestedScroll.
927 * the height is relative to the bottom of screen.
928 */
GetMaxSheetHeightBeforeDragUpdate()929 float SheetPresentationPattern::GetMaxSheetHeightBeforeDragUpdate()
930 {
931 if (IsCurSheetNeedHalfFoldHover()) {
932 return GetPageHeightWithoutOffset() - sheetOffsetY_;
933 }
934 auto sheetDetentsSize = sheetDetentHeight_.size();
935 if (sheetDetentsSize <= 0) {
936 TAG_LOGW(AceLogTag::ACE_SHEET, "sheetDetentsSize is nonPositive");
937 return 0.0f;
938 }
939 // The value can be returned in other scenarios as follows:
940 // 1. bottom sheet tyle : maxHeight is maxDetent.
941 // 2. center and other sheet tyle, except for popup tyle :
942 // maxHeight is the height of the top left corner of sheet from the bottom of screen
943 // 3. scene in setting offsetY : add offsetY to the following value
944 return sheetDetentHeight_[sheetDetentsSize - 1];
945 }
946
947 /**
948 * @brief Get the height before drag or nestedScroll.
949 * the height is relative to the bottom of screen.
950 */
GetSheetHeightBeforeDragUpdate()951 float SheetPresentationPattern::GetSheetHeightBeforeDragUpdate()
952 {
953 if (IsCurSheetNeedHalfFoldHover()) {
954 return GetPageHeightWithoutOffset() - sheetOffsetY_;
955 }
956 // height_ : from the bottom of screen, after the sheet entry action has ended.
957 // sheetHeightUp_ : increased height to avoid soft keyboard.
958 // -bottomOffsetY_ : increased height by setting offsetY. bottomOffsetY_ is a negative number.
959 return height_ + sheetHeightUp_ - bottomOffsetY_;
960 }
961
UpdateSheetTransitionOffset()962 float SheetPresentationPattern::UpdateSheetTransitionOffset()
963 {
964 // dentets greater than 1 and no rebound
965 if (!WillSpringBack() && sheetDetentHeight_.size() > 1) {
966 // When avoiding keyboards
967 // don't consider the height difference introduced by avoidance after switching detents
968 sheetHeightUp_ = 0.0f;
969 }
970 // apply to springBack scene
971 // return the offset before drag
972 auto offset = GetPageHeightWithoutOffset() - GetSheetHeightBeforeDragUpdate();
973 return offset;
974 }
975
SheetTransition(bool isTransitionIn,float dragVelocity)976 void SheetPresentationPattern::SheetTransition(bool isTransitionIn, float dragVelocity)
977 {
978 bool isNeedChangeScrollHeight = scrollSizeMode_ == ScrollSizeMode::CONTINUOUS && isDirectionUp_;
979 if ((HasOnHeightDidChange() && IsSheetBottomStyle() && isTransitionIn && isNeedProcessHeight_)
980 || isNeedChangeScrollHeight) {
981 ModifyFireSheetTransition(dragVelocity);
982 return;
983 }
984 auto host = GetHost();
985 CHECK_NULL_VOID(host);
986 AnimationOption option;
987 const RefPtr<InterpolatingSpring> curve = AceType::MakeRefPtr<InterpolatingSpring>(
988 dragVelocity / SHEET_VELOCITY_THRESHOLD, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
989 option.SetCurve(curve);
990 option.SetFillMode(FillMode::FORWARDS);
991 auto offset = UpdateSheetTransitionOffset();
992 if (!isTransitionIn) {
993 const auto& overlayManager = GetOverlayManager();
994 CHECK_NULL_VOID(overlayManager);
995 auto maskNode = overlayManager->GetSheetMask(host);
996 if (maskNode) {
997 overlayManager->PlaySheetMaskTransition(maskNode, false);
998 }
999 }
1000 option.SetOnFinishEvent([weak = AceType::WeakClaim(this), isTransitionIn]() {
1001 auto pattern = weak.Upgrade();
1002 CHECK_NULL_VOID(pattern);
1003 if (isTransitionIn) {
1004 if (!pattern->GetAnimationBreak()) {
1005 pattern->SetAnimationProcess(false);
1006 pattern->ChangeSheetPage(pattern->height_);
1007 } else {
1008 pattern->isAnimationBreak_ = false;
1009 }
1010 pattern->AvoidAiBar();
1011 pattern->FireOnDetentsDidChange(pattern->height_);
1012 pattern->isSpringBack_ = false;
1013 } else {
1014 pattern->SetAnimationProcess(false);
1015 const auto& overlayManager = pattern->GetOverlayManager();
1016 CHECK_NULL_VOID(overlayManager);
1017 auto host = pattern->GetHost();
1018 CHECK_NULL_VOID(host);
1019 overlayManager->FireAutoSave(host);
1020 overlayManager->DestroySheet(host, pattern->GetSheetKey());
1021 pattern->FireCallback("false");
1022 }
1023 });
1024 StartSheetTransitionAnimation(option, isTransitionIn, offset);
1025 }
1026
SheetInteractiveDismiss(BindSheetDismissReason dismissReason,float dragVelocity)1027 void SheetPresentationPattern::SheetInteractiveDismiss(BindSheetDismissReason dismissReason, float dragVelocity)
1028 {
1029 isDirectionUp_ = false;
1030 if (HasShouldDismiss() || HasOnWillDismiss()) {
1031 const auto& overlayManager = GetOverlayManager();
1032 CHECK_NULL_VOID(overlayManager);
1033 overlayManager->SetDismissTarget(DismissTarget(sheetKey_));
1034 auto host = GetHost();
1035 CHECK_NULL_VOID(host);
1036 SheetManager::GetInstance().SetDismissSheet(host->GetId());
1037 if (dismissReason == BindSheetDismissReason::SLIDE_DOWN) {
1038 ProcessColumnRect(height_);
1039 isSpringBack_ = true;
1040 if (HasSheetSpringBack()) {
1041 CallSheetSpringBack();
1042 } else {
1043 isDismissProcess_ = false;
1044 SheetTransition(true);
1045 }
1046 }
1047 CallShouldDismiss();
1048 CallOnWillDismiss(static_cast<int32_t>(dismissReason));
1049 } else {
1050 DismissTransition(false, dragVelocity);
1051 }
1052 }
1053
DismissTransition(bool isTransitionIn,float dragVelocity)1054 void SheetPresentationPattern::DismissTransition(bool isTransitionIn, float dragVelocity)
1055 {
1056 isDismissProcess_ = true;
1057 const auto& overlayManager = GetOverlayManager();
1058 CHECK_NULL_VOID(overlayManager);
1059 overlayManager->ModalPageLostFocus(GetHost());
1060 if (!isTransitionIn) {
1061 OnWillDisappear();
1062 }
1063 auto sheetType = GetSheetType();
1064 if (sheetType == SheetType::SHEET_POPUP) {
1065 BubbleStyleSheetTransition(isTransitionIn);
1066 } else {
1067 SheetTransition(isTransitionIn, dragVelocity);
1068 }
1069 }
1070
ChangeScrollHeight(float height)1071 void SheetPresentationPattern::ChangeScrollHeight(float height)
1072 {
1073 auto host = GetHost();
1074 CHECK_NULL_VOID(host);
1075 auto geometryNode = host->GetGeometryNode();
1076 CHECK_NULL_VOID(geometryNode);
1077 auto operationNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
1078 CHECK_NULL_VOID(operationNode);
1079 auto perationGeometryNode = operationNode->GetGeometryNode();
1080 CHECK_NULL_VOID(perationGeometryNode);
1081 auto operationHeight = perationGeometryNode->GetFrameSize().Height();
1082 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
1083 CHECK_NULL_VOID(scrollNode);
1084 auto scrollProps = scrollNode->GetLayoutProperty<ScrollLayoutProperty>();
1085 CHECK_NULL_VOID(scrollProps);
1086 auto scrollHeight = height - operationHeight - resizeDecreasedHeight_;
1087 auto sheetType = GetSheetType();
1088 if ((sheetType == SheetType::SHEET_POPUP) || (sheetType == SheetType::SHEET_CENTER)) {
1089 auto sheetHeight = geometryNode->GetFrameSize().Height();
1090 scrollHeight = sheetHeight - operationHeight - resizeDecreasedHeight_;
1091 }
1092 scrollProps->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(scrollHeight)));
1093 scrollNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1094 }
1095
UpdateDragBarStatus()1096 void SheetPresentationPattern::UpdateDragBarStatus()
1097 {
1098 auto host = GetHost();
1099 CHECK_NULL_VOID(host);
1100 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1101 CHECK_NULL_VOID(layoutProperty);
1102 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1103 auto showDragIndicator = sheetStyle.showDragBar.value_or(true);
1104
1105 auto titleColumn = DynamicCast<FrameNode>(host->GetFirstChild());
1106 CHECK_NULL_VOID(titleColumn);
1107 auto sheetDragBar = DynamicCast<FrameNode>(titleColumn->GetFirstChild());
1108 CHECK_NULL_VOID(sheetDragBar);
1109 auto dragBarLayoutProperty = sheetDragBar->GetLayoutProperty();
1110 CHECK_NULL_VOID(dragBarLayoutProperty);
1111 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1112 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::GONE);
1113 sheetDragBar->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1114 return;
1115 }
1116 if (IsSheetBottomStyle() && (sheetDetentHeight_.size() > 1)) {
1117 if (sheetStyle.isTitleBuilder.has_value()) {
1118 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
1119 } else {
1120 dragBarLayoutProperty->UpdateVisibility(showDragIndicator ? VisibleType::VISIBLE : VisibleType::GONE);
1121 }
1122 } else {
1123 if (sheetStyle.isTitleBuilder.has_value()) {
1124 dragBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
1125 } else {
1126 dragBarLayoutProperty->UpdateVisibility(VisibleType::GONE);
1127 }
1128 }
1129 sheetDragBar->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1130 }
1131
GetCloseIconPosX(const SizeF & sheetSize,const RefPtr<SheetTheme> & sheetTheme)1132 float SheetPresentationPattern::GetCloseIconPosX(const SizeF& sheetSize, const RefPtr<SheetTheme>& sheetTheme)
1133 {
1134 auto closeIconX = sheetSize.Width() - static_cast<float>(SHEET_CLOSE_ICON_WIDTH.ConvertToPx()) -
1135 static_cast<float>(sheetTheme->GetTitleTextMargin().ConvertToPx());
1136 if (AceApplicationInfo::GetInstance().IsRightToLeft() &&
1137 AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1138 closeIconX = static_cast<float>(sheetTheme->GetTitleTextMargin().ConvertToPx());
1139 }
1140 return closeIconX;
1141 }
1142
IsShowCloseIcon()1143 bool SheetPresentationPattern::IsShowCloseIcon()
1144 {
1145 auto host = GetHost();
1146 CHECK_NULL_RETURN(host, false);
1147 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1148 CHECK_NULL_RETURN(layoutProperty, false);
1149 return layoutProperty->GetSheetStyleValue().showCloseIcon.value_or(true);
1150 }
1151
GetTitleNode() const1152 RefPtr<FrameNode> SheetPresentationPattern::GetTitleNode() const
1153 {
1154 auto host = GetHost();
1155 CHECK_NULL_RETURN(host, nullptr);
1156 auto operationNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
1157 CHECK_NULL_RETURN(operationNode, nullptr);
1158 return DynamicCast<FrameNode>(operationNode->GetChildAtIndex(1));
1159 }
1160
UpdateTitlePadding()1161 void SheetPresentationPattern::UpdateTitlePadding()
1162 {
1163 auto host = GetHost();
1164 CHECK_NULL_VOID(host);
1165 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1166 CHECK_NULL_VOID(layoutProperty);
1167 if (!layoutProperty->GetSheetStyleValue().isTitleBuilder.has_value()) {
1168 return;
1169 }
1170
1171 auto titleNode = GetTitleNode();
1172 CHECK_NULL_VOID(titleNode);
1173 auto titleLayoutProperty = DynamicCast<LinearLayoutProperty>(titleNode->GetLayoutProperty());
1174 CHECK_NULL_VOID(titleLayoutProperty);
1175 auto pipeline = host->GetContext();
1176 CHECK_NULL_VOID(pipeline);
1177 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1178 CHECK_NULL_VOID(sheetTheme);
1179 auto showCloseIcon = true;
1180 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN)) {
1181 showCloseIcon = IsShowCloseIcon();
1182 }
1183 PaddingProperty padding;
1184
1185 // The title bar area is reserved for the close button area size by default.
1186 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1187 auto sheetCloseIconTitleSpace = sheetTheme->IsOuterBorderEnable() ? 0.0_vp : SHEET_CLOSE_ICON_TITLE_SPACE_NEW;
1188 padding.end = CalcLength(showCloseIcon ? sheetCloseIconTitleSpace + SHEET_CLOSE_ICON_WIDTH : 0.0_vp);
1189 } else {
1190 padding.right = CalcLength(SHEET_CLOSE_ICON_TITLE_SPACE + SHEET_CLOSE_ICON_WIDTH);
1191 }
1192 titleLayoutProperty->UpdatePadding(padding);
1193 auto titleColumnPattern = titleNode->GetPattern<LinearLayoutPattern>();
1194 CHECK_NULL_VOID(titleColumnPattern);
1195 titleColumnPattern->CheckLocalized();
1196 titleNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1197 }
1198
UpdateCloseIconStatus()1199 void SheetPresentationPattern::UpdateCloseIconStatus()
1200 {
1201 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1202 TAG_LOGI(AceLogTag::ACE_SHEET, "PlatformVersion less or equal to version 10");
1203 return;
1204 }
1205 auto host = GetHost();
1206 CHECK_NULL_VOID(host);
1207 auto pipeline = PipelineContext::GetCurrentContext();
1208 CHECK_NULL_VOID(pipeline);
1209 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1210 CHECK_NULL_VOID(sheetTheme);
1211 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1212 CHECK_NULL_VOID(layoutProperty);
1213 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1214 auto showCloseIcon = IsShowCloseIcon();
1215 auto sheetCloseIcon = DynamicCast<FrameNode>(host->GetChildAtIndex(2));
1216 CHECK_NULL_VOID(sheetCloseIcon);
1217 auto geometryNode = host->GetGeometryNode();
1218 CHECK_NULL_VOID(geometryNode);
1219 auto size = geometryNode->GetFrameSize();
1220 auto closeIconX = GetCloseIconPosX(size, sheetTheme);
1221 auto closeIconY = static_cast<float>(sheetTheme->GetTitleTextMargin().ConvertToPx());
1222 OffsetT<Dimension> positionOffset;
1223 positionOffset.SetX(Dimension(closeIconX));
1224 auto sheetType = GetSheetType();
1225 if (sheetType == SheetType::SHEET_POPUP) {
1226 positionOffset.SetY(Dimension(closeIconY) + SHEET_ARROW_HEIGHT);
1227 } else {
1228 positionOffset.SetY(Dimension(closeIconY));
1229 }
1230 auto renderContext = sheetCloseIcon->GetRenderContext();
1231 CHECK_NULL_VOID(renderContext);
1232 TAG_LOGD(AceLogTag::ACE_SHEET, "sheet closeIcon positionOffset info, x is: %{public}s, y is: %{public}s",
1233 positionOffset.GetX().ToString().c_str(), positionOffset.GetY().ToString().c_str());
1234 renderContext->UpdatePosition(positionOffset);
1235 auto iconLayoutProperty = sheetCloseIcon->GetLayoutProperty();
1236 CHECK_NULL_VOID(iconLayoutProperty);
1237 iconLayoutProperty->UpdateVisibility(showCloseIcon ? VisibleType::VISIBLE : VisibleType::INVISIBLE);
1238 sheetCloseIcon->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1239 }
1240
UpdateSheetTitle()1241 void SheetPresentationPattern::UpdateSheetTitle()
1242 {
1243 auto host = GetHost();
1244 CHECK_NULL_VOID(host);
1245 auto pipeline = PipelineContext::GetCurrentContext();
1246 CHECK_NULL_VOID(pipeline);
1247 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1248 CHECK_NULL_VOID(layoutProperty);
1249 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1250 if (sheetStyle.sheetTitle.has_value()) {
1251 auto titleId = GetTitleId();
1252 auto titleNode = DynamicCast<FrameNode>(ElementRegister::GetInstance()->GetNodeById(titleId));
1253 CHECK_NULL_VOID(titleNode);
1254 auto titleProp = titleNode->GetLayoutProperty<TextLayoutProperty>();
1255 CHECK_NULL_VOID(titleProp);
1256 titleProp->UpdateContent(sheetStyle.sheetTitle.value());
1257 if (pipeline->GetFontScale() != scale_) {
1258 titleNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1259 }
1260 titleNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1261 if (sheetStyle.sheetSubtitle.has_value()) {
1262 auto subtitleId = GetSubtitleId();
1263 auto subtitleNode = DynamicCast<FrameNode>(ElementRegister::GetInstance()->GetNodeById(subtitleId));
1264 CHECK_NULL_VOID(subtitleNode);
1265 auto subtitleProp = subtitleNode->GetLayoutProperty<TextLayoutProperty>();
1266 CHECK_NULL_VOID(subtitleProp);
1267 subtitleProp->UpdateContent(sheetStyle.sheetSubtitle.value());
1268 subtitleNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1269 }
1270 }
1271 }
1272
UpdateFontScaleStatus()1273 void SheetPresentationPattern::UpdateFontScaleStatus()
1274 {
1275 auto host = GetHost();
1276 CHECK_NULL_VOID(host);
1277 auto pipeline = PipelineContext::GetCurrentContext();
1278 CHECK_NULL_VOID(pipeline);
1279 auto layoutProperty = DynamicCast<SheetPresentationProperty>(host->GetLayoutProperty());
1280 CHECK_NULL_VOID(layoutProperty);
1281 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1282 if (pipeline->GetFontScale() != scale_) {
1283 auto operationNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
1284 CHECK_NULL_VOID(operationNode);
1285 auto titleColumnNode = DynamicCast<FrameNode>(operationNode->GetChildAtIndex(1));
1286 CHECK_NULL_VOID(titleColumnNode);
1287 auto layoutProps = operationNode->GetLayoutProperty<LinearLayoutProperty>();
1288 CHECK_NULL_VOID(layoutProps);
1289 auto titleLayoutProps = titleColumnNode->GetLayoutProperty<LinearLayoutProperty>();
1290 CHECK_NULL_VOID(titleLayoutProps);
1291 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1292 CHECK_NULL_VOID(sheetTheme);
1293 bool isSheetHasNoTitle = !sheetStyle.isTitleBuilder.has_value();
1294 bool isFontScaledInSystemTitle = sheetStyle.isTitleBuilder.has_value() && !sheetStyle.isTitleBuilder.value() &&
1295 GreatNotEqual(pipeline->GetFontScale(), sheetTheme->GetSheetNormalScale());
1296 if (isSheetHasNoTitle || isFontScaledInSystemTitle) {
1297 layoutProps->ClearUserDefinedIdealSize(false, true);
1298 titleLayoutProps->ClearUserDefinedIdealSize(false, true);
1299 } else if (sheetStyle.isTitleBuilder.has_value()) {
1300 layoutProps->UpdateUserDefinedIdealSize(
1301 CalcSize(std::nullopt, CalcLength(SHEET_OPERATION_AREA_HEIGHT - SHEET_TITLE_AERA_MARGIN)));
1302 titleLayoutProps->UpdateUserDefinedIdealSize(
1303 CalcSize(std::nullopt, CalcLength(SHEET_OPERATION_AREA_HEIGHT)));
1304 if (sheetStyle.sheetSubtitle.has_value()) {
1305 layoutProps->UpdateUserDefinedIdealSize(
1306 CalcSize(std::nullopt, CalcLength(SHEET_OPERATION_AREA_HEIGHT_DOUBLE - SHEET_TITLE_AERA_MARGIN)));
1307 titleLayoutProps->UpdateUserDefinedIdealSize(
1308 CalcSize(std::nullopt,
1309 CalcLength(SHEET_OPERATION_AREA_HEIGHT_DOUBLE - SHEET_DOUBLE_TITLE_BOTTON_MARGIN)));
1310 }
1311 }
1312 UpdateSheetTitle();
1313 scale_ = pipeline->GetFontScale();
1314 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1315 }
1316 }
1317
OnColorConfigurationUpdate()1318 void SheetPresentationPattern::OnColorConfigurationUpdate()
1319 {
1320 auto host = GetHost();
1321 CHECK_NULL_VOID(host);
1322 auto pipeline = PipelineContext::GetCurrentContext();
1323 CHECK_NULL_VOID(pipeline);
1324 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1325 CHECK_NULL_VOID(sheetTheme);
1326 auto sheetCloseIcon = DynamicCast<FrameNode>(host->GetChildAtIndex(2));
1327 CHECK_NULL_VOID(sheetCloseIcon);
1328 auto renderContext = sheetCloseIcon->GetRenderContext();
1329 CHECK_NULL_VOID(renderContext);
1330 renderContext->UpdateBackgroundColor(sheetTheme->GetCloseIconColor());
1331 sheetCloseIcon->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1332 auto iconNode = DynamicCast<FrameNode>(sheetCloseIcon->GetChildAtIndex(0));
1333 CHECK_NULL_VOID(iconNode);
1334
1335 // when api >= 12, use symbol format image, else use image format.
1336 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
1337 SystemProperties::IsNeedSymbol()) {
1338 auto symbolLayoutProperty = iconNode->GetLayoutProperty<TextLayoutProperty>();
1339 CHECK_NULL_VOID(symbolLayoutProperty);
1340 symbolLayoutProperty->UpdateSymbolColorList({sheetTheme->GetCloseIconSymbolColor()});
1341 } else {
1342 auto imagePaintProperty = iconNode->GetPaintProperty<ImageRenderProperty>();
1343 CHECK_NULL_VOID(imagePaintProperty);
1344 imagePaintProperty->UpdateSvgFillColor(sheetTheme->GetCloseIconImageColor());
1345 }
1346 iconNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1347 }
1348
GetWrapperHeight()1349 float SheetPresentationPattern::GetWrapperHeight()
1350 {
1351 auto host = GetHost();
1352 CHECK_NULL_RETURN(host, 0.0f);
1353 auto sheetWrapper = host->GetParent();
1354 CHECK_NULL_RETURN(sheetWrapper, 0.0f);
1355 auto sheetWrapperNode = AceType::DynamicCast<FrameNode>(sheetWrapper->GetParent());
1356 CHECK_NULL_RETURN(sheetWrapperNode, 0.0f);
1357 auto sheetWrapperGeometryNode = sheetWrapperNode->GetGeometryNode();
1358 CHECK_NULL_RETURN(sheetWrapperGeometryNode, 0.0f);
1359 return sheetWrapperGeometryNode->GetFrameSize().Height();
1360 }
1361
SheetHeightNeedChanged()1362 bool SheetPresentationPattern::SheetHeightNeedChanged()
1363 {
1364 auto host = GetHost();
1365 CHECK_NULL_RETURN(host, false);
1366 auto sheetGeometryNode = host->GetGeometryNode();
1367 CHECK_NULL_RETURN(sheetGeometryNode, false);
1368 if (!NearEqual(sheetGeometryNode->GetFrameSize().Height(), sheetHeight_) ||
1369 !NearEqual(GetWrapperHeight(), wrapperHeight_)) {
1370 return true;
1371 }
1372 return false;
1373 }
1374
UpdateMaskBackgroundColor()1375 void SheetPresentationPattern::UpdateMaskBackgroundColor()
1376 {
1377 auto host = GetHost();
1378 CHECK_NULL_VOID(host);
1379 auto pipeline = host->GetContext();
1380 CHECK_NULL_VOID(pipeline);
1381 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1382 CHECK_NULL_VOID(sheetTheme);
1383 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
1384 CHECK_NULL_VOID(layoutProperty);
1385 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1386 sheetMaskColor_ = sheetStyle.maskColor.value_or(sheetTheme->GetMaskColor());
1387 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1388 if (sheetStyle.maskColor.has_value()) {
1389 sheetMaskColor_ = sheetStyle.maskColor.value();
1390 } else {
1391 sheetMaskColor_ = Color::TRANSPARENT;
1392 }
1393 } else {
1394 if ((!sheetStyle.interactive.has_value() && GetSheetType() == SheetType::SHEET_POPUP) ||
1395 sheetStyle.interactive.value_or(false)) {
1396 sheetMaskColor_ = Color::TRANSPARENT;
1397 }
1398 }
1399 }
1400
UpdateMaskBackgroundColorRender()1401 void SheetPresentationPattern::UpdateMaskBackgroundColorRender()
1402 {
1403 auto host = GetHost();
1404 CHECK_NULL_VOID(host);
1405 UpdateMaskBackgroundColor();
1406 auto maskNode = DynamicCast<FrameNode>(host->GetParent());
1407 CHECK_NULL_VOID(maskNode);
1408 auto maskRenderContext = maskNode->GetRenderContext();
1409 CHECK_NULL_VOID(maskRenderContext);
1410 maskRenderContext->UpdateBackgroundColor(sheetMaskColor_);
1411 }
1412
FireCommonCallback()1413 void SheetPresentationPattern::FireCommonCallback()
1414 {
1415 auto host = GetHost();
1416 CHECK_NULL_VOID(host);
1417 FireOnTypeDidChange();
1418 FireOnWidthDidChange(host);
1419 FireOnHeightDidChange();
1420 }
1421
CheckSheetHeightChange()1422 void SheetPresentationPattern::CheckSheetHeightChange()
1423 {
1424 auto host = GetHost();
1425 CHECK_NULL_VOID(host);
1426 auto sheetGeometryNode = host->GetGeometryNode();
1427 CHECK_NULL_VOID(sheetGeometryNode);
1428 if (isFirstInit_) {
1429 sheetHeight_ = sheetGeometryNode->GetFrameSize().Height();
1430 wrapperHeight_ = GetWrapperHeight();
1431 sheetType_ = GetSheetType();
1432 isFirstInit_ = false;
1433 } else {
1434 if (sheetType_ != GetSheetType()) {
1435 if (sheetType_ == SheetType::SHEET_POPUP) {
1436 MarkSheetPageNeedRender();
1437 }
1438 SetSheetBorderWidth();
1439 }
1440 if (SheetHeightNeedChanged() || (sheetType_ != GetSheetType()) || windowChanged_ || topSafeAreaChanged_) {
1441 sheetType_ = GetSheetType();
1442 sheetHeight_ = sheetGeometryNode->GetFrameSize().Height();
1443 wrapperHeight_ = GetWrapperHeight();
1444 const auto& overlayManager = GetOverlayManager();
1445 CHECK_NULL_VOID(overlayManager);
1446 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
1447 CHECK_NULL_VOID(layoutProperty);
1448 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1449 overlayManager->ComputeSheetOffset(sheetStyle, host);
1450 if (sheetType_ == SheetType::SHEET_POPUP) {
1451 auto renderContext = GetRenderContext();
1452 CHECK_NULL_VOID(renderContext);
1453 renderContext->UpdateTransformTranslate({ 0.0f, Dimension(sheetOffsetY_), 0.0f });
1454 renderContext->UpdateOpacity(SHEET_VISIABLE_ALPHA);
1455 FireCommonCallback();
1456 } else {
1457 overlayManager->PlaySheetTransition(host, true, false);
1458 }
1459 auto maskNode = overlayManager->GetSheetMask(host);
1460 if (maskNode) {
1461 UpdateMaskBackgroundColorRender();
1462 }
1463 windowChanged_ = false;
1464 topSafeAreaChanged_ = false;
1465 }
1466 }
1467 GetBuilderInitHeight();
1468 }
1469
IsCustomDetentsChanged(SheetStyle sheetStyle)1470 void SheetPresentationPattern::IsCustomDetentsChanged(SheetStyle sheetStyle)
1471 {
1472 unsigned int preDetentsSize = preDetents_.size();
1473 unsigned int userSetDetentsSize = sheetStyle.detents.size();
1474 // if preview detents size is not equal to the new one, set detents index to zero
1475 if (preDetentsSize != userSetDetentsSize) {
1476 detentsFinalIndex_ = 0;
1477 return;
1478 }
1479
1480 // check whether the new coming one's content is equal to the last time input
1481 unsigned int length = std::min(preDetentsSize, userSetDetentsSize);
1482 for (unsigned int index = 0; index < length; index++) {
1483 if (sheetStyle.detents[index] != preDetents_[index]) {
1484 // if detents has been changed, set detents index to zero
1485 detentsFinalIndex_ = 0;
1486 break;
1487 }
1488 }
1489 }
1490
InitSheetDetents()1491 void SheetPresentationPattern::InitSheetDetents()
1492 {
1493 // record input detents
1494 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
1495 CHECK_NULL_VOID(layoutProperty);
1496 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1497 IsCustomDetentsChanged(sheetStyle);
1498 preDetents_.clear();
1499 sheetDetentHeight_.clear();
1500 unSortedSheetDentents_.clear();
1501 float height = 0.0f;
1502 auto sheetNode = GetHost();
1503 CHECK_NULL_VOID(sheetNode);
1504 auto geometryNode = sheetNode->GetGeometryNode();
1505 CHECK_NULL_VOID(geometryNode);
1506 auto largeHeight = sheetMaxHeight_ - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
1507 auto sheetType = GetSheetType();
1508 auto sheetFrameHeight = geometryNode->GetFrameSize().Height();
1509 auto mediumSize = MEDIUM_SIZE;
1510 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1511 mediumSize = MEDIUM_SIZE_PRE;
1512 }
1513 switch (sheetType) {
1514 case SheetType::SHEET_BOTTOMLANDSPACE:
1515 if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
1516 height = sheetFrameHeight - SHEET_BLANK_MINI_HEIGHT.ConvertToPx();
1517 sheetDetentHeight_.emplace_back(height);
1518 break;
1519 }
1520 case SheetType::SHEET_BOTTOM:
1521 [[fallthrough]];
1522 case SheetType::SHEET_BOTTOM_FREE_WINDOW:
1523 if (sheetStyle.detents.size() <= 0) {
1524 height = InitialSingleGearHeight(sheetStyle);
1525 sheetDetentHeight_.emplace_back(height);
1526 break;
1527 }
1528 for (auto iter : sheetStyle.detents) {
1529 preDetents_.emplace_back(iter);
1530 if (iter.sheetMode.has_value()) {
1531 if (iter.sheetMode == SheetMode::MEDIUM) {
1532 height = pageHeight_ * mediumSize;
1533 } else if (iter.sheetMode == SheetMode::LARGE) {
1534 height = largeHeight;
1535 } else if (iter.sheetMode == SheetMode::AUTO) {
1536 height = GetFitContentHeight();
1537 height = GreatNotEqual(height, largeHeight) ? largeHeight : height;
1538 HandleFitContontChange(height);
1539 }
1540 } else {
1541 if (iter.height->Unit() == DimensionUnit::PERCENT) {
1542 height = iter.height->ConvertToPxWithSize(sheetMaxHeight_);
1543 } else {
1544 height = iter.height->ConvertToPx();
1545 }
1546 if (GreatNotEqual(height, largeHeight)) {
1547 height = largeHeight;
1548 } else if (LessNotEqual(height, 0)) {
1549 height = largeHeight;
1550 }
1551 }
1552 sheetDetentHeight_.emplace_back(height);
1553 unSortedSheetDentents_.emplace_back(height);
1554 }
1555 std::sort(sheetDetentHeight_.begin(), sheetDetentHeight_.end(), std::less<float>());
1556 sheetDetentHeight_.erase(
1557 std::unique(sheetDetentHeight_.begin(), sheetDetentHeight_.end()), sheetDetentHeight_.end());
1558 break;
1559 case SheetType::SHEET_CENTER:
1560 height = (centerHeight_ + pageHeight_) / SHEET_HALF_HEIGHT;
1561 sheetDetentHeight_.emplace_back(height);
1562 break;
1563 default:
1564 break;
1565 }
1566 }
1567
HandleFitContontChange(float height)1568 void SheetPresentationPattern::HandleFitContontChange(float height)
1569 {
1570 if ((NearEqual(height_, sheetFitContentHeight_)) && (!NearEqual(height, sheetFitContentHeight_))) {
1571 ChangeSheetHeight(height);
1572 ChangeSheetPage(height_);
1573 SheetTransition(true);
1574 }
1575 sheetFitContentHeight_ = height;
1576 }
1577
GetSheetType()1578 SheetType SheetPresentationPattern::GetSheetType()
1579 {
1580 if (!Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
1581 return SHEET_BOTTOM;
1582 }
1583 SheetType sheetType = SheetType::SHEET_BOTTOM;
1584 auto pipelineContext = PipelineContext::GetCurrentContext();
1585 CHECK_NULL_RETURN(pipelineContext, sheetType);
1586 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
1587 CHECK_NULL_RETURN(layoutProperty, sheetType);
1588 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1589 auto windowGlobalRect = pipelineContext->GetDisplayWindowRectInfo();
1590 TAG_LOGD(AceLogTag::ACE_SHEET, "GetSheetType displayWindowRect info is : %{public}s",
1591 windowGlobalRect.ToString().c_str());
1592 // only bottom when width is less than 600vp
1593 if ((windowGlobalRect.Width() < SHEET_DEVICE_WIDTH_BREAKPOINT.ConvertToPx()) ||
1594 (sheetStyle.sheetType.has_value() && sheetStyle.sheetType.value() == SheetType::SHEET_BOTTOM)) {
1595 return SheetType::SHEET_BOTTOM;
1596 }
1597 if (sheetThemeType_ == "auto") {
1598 GetSheetTypeWithAuto(sheetType);
1599 } else if (sheetThemeType_ == "popup") {
1600 GetSheetTypeWithPopup(sheetType);
1601 }
1602 return sheetType;
1603 }
1604
InitSheetMode()1605 void SheetPresentationPattern::InitSheetMode()
1606 {
1607 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
1608 CHECK_NULL_VOID(layoutProperty);
1609 auto sheetStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
1610 scrollSizeMode_ = sheetStyle.scrollSizeMode.value_or(ScrollSizeMode::FOLLOW_DETENT);
1611 keyboardAvoidMode_ = sheetStyle.sheetKeyboardAvoidMode.value_or(SheetKeyboardAvoidMode::TRANSLATE_AND_SCROLL);
1612 }
1613
GetSheetTypeWithAuto(SheetType & sheetType)1614 void SheetPresentationPattern::GetSheetTypeWithAuto(SheetType& sheetType)
1615 {
1616 auto rootHeight = PipelineContext::GetCurrentRootHeight();
1617 auto rootWidth = PipelineContext::GetCurrentRootWidth();
1618 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
1619 CHECK_NULL_VOID(layoutProperty);
1620 auto pipeline = PipelineContext::GetCurrentContext();
1621 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1622 CHECK_NULL_VOID(sheetTheme);
1623 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1624 #ifdef PREVIEW
1625 auto container = Container::Current();
1626 CHECK_NULL_VOID(container);
1627 if (container->IsFoldable() && container->GetCurrentFoldStatus() == FoldStatus::EXPAND) {
1628 #else
1629 // when big fold expand
1630 if (IsFoldExpand() && !sheetTheme->IsOnlyBottom()) {
1631 #endif
1632 sheetType = SheetType::SHEET_CENTER;
1633 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_FOURTEEN) &&
1634 sheetStyle.sheetType.has_value() && sheetStyle.sheetType.value() == SheetType::SHEET_POPUP) {
1635 sheetType = SheetType::SHEET_POPUP;
1636 return;
1637 }
1638 } else {
1639 if (LessNotEqual(rootHeight, rootWidth)) {
1640 sheetType = SheetType::SHEET_BOTTOMLANDSPACE;
1641 } else {
1642 sheetType = SheetType::SHEET_BOTTOM;
1643 }
1644 }
1645 }
1646
1647 void SheetPresentationPattern::GetSheetTypeWithPopup(SheetType& sheetType)
1648 {
1649 auto pipelineContext = PipelineContext::GetCurrentContext();
1650 auto rootWidth = PipelineContext::GetCurrentRootWidth();
1651 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
1652 CHECK_NULL_VOID(layoutProperty);
1653 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1654 #ifdef PREVIEW
1655 rootWidth = pipelineContext->GetDisplayWindowRectInfo().Width();
1656 #endif
1657 if (GreatOrEqual(rootWidth, SHEET_PC_DEVICE_WIDTH_BREAKPOINT.ConvertToPx())) {
1658 if (sheetStyle.sheetType.has_value()) {
1659 sheetType = sheetStyle.sheetType.value();
1660 } else {
1661 sheetType = SheetType::SHEET_POPUP;
1662 }
1663 } else if (GreatOrEqual(rootWidth, SHEET_DEVICE_WIDTH_BREAKPOINT.ConvertToPx()) &&
1664 LessNotEqual(rootWidth, SHEET_PC_DEVICE_WIDTH_BREAKPOINT.ConvertToPx())) {
1665 if (sheetStyle.sheetType.has_value()) {
1666 sheetType = sheetStyle.sheetType.value();
1667 } else {
1668 sheetType = SheetType::SHEET_CENTER;
1669 }
1670 } else {
1671 sheetType = SheetType::SHEET_BOTTOM_FREE_WINDOW;
1672 }
1673 if (sheetType == SheetType::SHEET_POPUP && !sheetKey_.hasValidTargetNode) {
1674 sheetType = SheetType::SHEET_CENTER;
1675 }
1676 }
1677
1678 void SheetPresentationPattern::BubbleStyleSheetTransition(bool isTransitionIn)
1679 {
1680 auto host = this->GetHost();
1681 CHECK_NULL_VOID(host);
1682 if (!isTransitionIn) {
1683 const auto& overlayManager = GetOverlayManager();
1684 CHECK_NULL_VOID(overlayManager);
1685 auto maskNode = overlayManager->GetSheetMask(host);
1686 if (maskNode) {
1687 overlayManager->PlaySheetMaskTransition(maskNode, false);
1688 }
1689 StartOffsetExitingAnimation();
1690 StartAlphaExitingAnimation(
1691 [weakNode = AceType::WeakClaim(AceType::RawPtr(host)), weakPattern = AceType::WeakClaim(this)]() {
1692 auto node = weakNode.Upgrade();
1693 CHECK_NULL_VOID(node);
1694 auto pattern = weakPattern.Upgrade();
1695 CHECK_NULL_VOID(pattern);
1696 const auto& overlayManager = pattern->GetOverlayManager();
1697 CHECK_NULL_VOID(overlayManager);
1698 overlayManager->FireAutoSave(node);
1699 overlayManager->DestroySheet(node, pattern->GetSheetKey());
1700 pattern->FireCallback("false");
1701 });
1702 overlayManager->CleanSheet(host, GetSheetKey());
1703 }
1704 }
1705
1706 void SheetPresentationPattern::StartOffsetEnteringAnimation()
1707 {
1708 AnimationOption optionPosition;
1709 optionPosition.SetDuration(SHEET_ENTRY_ANIMATION_DURATION);
1710 optionPosition.SetCurve(Curves::FRICTION);
1711 AnimationUtils::Animate(
1712 optionPosition,
1713 [weak = WeakClaim(this)]() {
1714 auto pattern = weak.Upgrade();
1715 CHECK_NULL_VOID(pattern);
1716 auto renderContext = pattern->GetRenderContext();
1717 CHECK_NULL_VOID(renderContext);
1718 renderContext->UpdateTransformTranslate({ 0.0f, Dimension(pattern->sheetOffsetY_), 0.0f });
1719 },
1720 nullptr);
1721 }
1722
1723 void SheetPresentationPattern::StartAlphaEnteringAnimation(std::function<void()> finish)
1724 {
1725 AnimationOption optionAlpha;
1726 optionAlpha.SetDuration(SHEET_ENTRY_ANIMATION_DURATION);
1727 optionAlpha.SetCurve(Curves::SHARP);
1728 AnimationUtils::Animate(
1729 optionAlpha,
1730 [weak = WeakClaim(this)]() {
1731 auto pattern = weak.Upgrade();
1732 CHECK_NULL_VOID(pattern);
1733 auto renderContext = pattern->GetRenderContext();
1734 CHECK_NULL_VOID(renderContext);
1735 renderContext->UpdateOpacity(SHEET_VISIABLE_ALPHA);
1736 },
1737 finish);
1738 }
1739
1740 void SheetPresentationPattern::StartOffsetExitingAnimation()
1741 {
1742 AnimationOption optionPosition;
1743 optionPosition.SetDuration(SHEET_EXIT_ANIMATION_DURATION);
1744 optionPosition.SetCurve(Curves::FRICTION);
1745 AnimationUtils::Animate(
1746 optionPosition,
1747 [weak = WeakClaim(this)]() {
1748 auto pattern = weak.Upgrade();
1749 CHECK_NULL_VOID(pattern);
1750 auto renderContext = pattern->GetRenderContext();
1751 CHECK_NULL_VOID(renderContext);
1752 renderContext->UpdateTransformTranslate(
1753 { 0.0f, Dimension(pattern->sheetOffsetY_ - SHEET_INVISIABLE_OFFSET), 0.0f });
1754 },
1755 nullptr);
1756 }
1757
1758 void SheetPresentationPattern::StartAlphaExitingAnimation(std::function<void()> finish)
1759 {
1760 AnimationOption optionAlpha;
1761 optionAlpha.SetDuration(SHEET_EXIT_ANIMATION_DURATION);
1762 optionAlpha.SetCurve(Curves::SHARP);
1763 AnimationUtils::Animate(
1764 optionAlpha,
1765 [weak = WeakClaim(this)]() {
1766 auto pattern = weak.Upgrade();
1767 CHECK_NULL_VOID(pattern);
1768 auto renderContext = pattern->GetRenderContext();
1769 CHECK_NULL_VOID(renderContext);
1770 renderContext->UpdateOpacity(SHEET_INVISIABLE_ALPHA);
1771 },
1772 finish);
1773 }
1774
1775 RefPtr<RenderContext> SheetPresentationPattern::GetRenderContext()
1776 {
1777 auto frameNode = GetHost();
1778 CHECK_NULL_RETURN(frameNode, nullptr);
1779 return frameNode->GetRenderContext();
1780 }
1781
1782 bool SheetPresentationPattern::PostTask(const TaskExecutor::Task& task, const std::string& name)
1783 {
1784 auto pipeline = PipelineBase::GetCurrentContext();
1785 CHECK_NULL_RETURN(pipeline, false);
1786 auto taskExecutor = pipeline->GetTaskExecutor();
1787 CHECK_NULL_RETURN(taskExecutor, false);
1788 return taskExecutor->PostTask(task, TaskExecutor::TaskType::UI, name);
1789 }
1790
1791 void SheetPresentationPattern::ResetToInvisible()
1792 {
1793 auto renderContext = GetRenderContext();
1794 CHECK_NULL_VOID(renderContext);
1795 renderContext->UpdateOpacity(SHEET_INVISIABLE_ALPHA);
1796 renderContext->UpdateTransformTranslate({ 0.0f, Dimension(sheetOffsetY_ - SHEET_INVISIABLE_OFFSET), 0.0f });
1797 }
1798
1799 bool SheetPresentationPattern::IsFoldExpand()
1800 {
1801 bool isExpand = false;
1802 auto container = Container::Current();
1803 CHECK_NULL_RETURN(container, false);
1804 auto foldStatus = container->GetCurrentFoldStatus();
1805 isExpand = foldStatus != FoldStatus::FOLDED && foldStatus != FoldStatus::UNKNOWN;
1806 if (isExpand) {
1807 TAG_LOGD(AceLogTag::ACE_SHEET, "Get Fold status IsFoldExpand is true");
1808 return true;
1809 } else {
1810 return false;
1811 }
1812 }
1813
1814 void SheetPresentationPattern::ChangeSheetHeight(float height)
1815 {
1816 if (!NearEqual(height_, height)) {
1817 isDirectionUp_ = GreatNotEqual(height, height_);
1818 height_ = height;
1819 SetCurrentHeightToOverlay(height_);
1820 }
1821 }
1822
1823 void SheetPresentationPattern::StartSheetTransitionAnimation(
1824 const AnimationOption& option, bool isTransitionIn, float offset)
1825 {
1826 auto host = GetHost();
1827 CHECK_NULL_VOID(host);
1828 auto context = host->GetRenderContext();
1829 CHECK_NULL_VOID(context);
1830 isAnimationProcess_ = true;
1831 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
1832 CHECK_NULL_VOID(sheetPattern);
1833 auto sheetParent = DynamicCast<FrameNode>(host->GetParent());
1834 CHECK_NULL_VOID(sheetParent);
1835 if (isTransitionIn) {
1836 animation_ = AnimationUtils::StartAnimation(
1837 option,
1838 [context, offset]() {
1839 if (context) {
1840 context->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
1841 }
1842 },
1843 option.GetOnFinishEvent());
1844 } else {
1845 host->OnAccessibilityEvent(
1846 AccessibilityEventType::PAGE_CLOSE, WindowsContentChangeTypes::CONTENT_CHANGE_TYPE_SUBTREE);
1847 sheetParent->GetEventHub<EventHub>()->GetOrCreateGestureEventHub()->SetHitTestMode(
1848 HitTestMode::HTMTRANSPARENT);
1849 animation_ = AnimationUtils::StartAnimation(
1850 option,
1851 [context, this]() {
1852 if (context) {
1853 DismissSheetShadow(context);
1854 context->UpdateTransformTranslate({ 0.0f, pageHeight_, 0.0f });
1855 }
1856 },
1857 option.GetOnFinishEvent());
1858 const auto& overlayManager = GetOverlayManager();
1859 CHECK_NULL_VOID(overlayManager);
1860 overlayManager->CleanSheet(host, GetSheetKey());
1861 }
1862 }
1863
1864 void SheetPresentationPattern::DismissSheetShadow(const RefPtr<RenderContext>& context)
1865 {
1866 auto shadow = context->GetBackShadow();
1867 if (!shadow.has_value()) {
1868 shadow = Shadow::CreateShadow(ShadowStyle::None);
1869 }
1870 auto color = shadow->GetColor();
1871 auto newColor = color.ChangeAlpha(0);
1872 shadow->SetColor(newColor);
1873 context->UpdateBackShadow(shadow.value());
1874 }
1875
1876 void SheetPresentationPattern::ClipSheetNode()
1877 {
1878 auto host = GetHost();
1879 CHECK_NULL_VOID(host);
1880 auto geometryNode = host->GetGeometryNode();
1881 CHECK_NULL_VOID(geometryNode);
1882 auto sheetSize = geometryNode->GetFrameSize();
1883 auto pipeline = PipelineContext::GetCurrentContext();
1884 CHECK_NULL_VOID(pipeline);
1885 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
1886 CHECK_NULL_VOID(sheetTheme);
1887 auto renderContext = host->GetRenderContext();
1888 CHECK_NULL_VOID(renderContext);
1889 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
1890 CHECK_NULL_VOID(layoutProperty);
1891 auto sheetStyle = layoutProperty->GetSheetStyleValue();
1892 ResetClipShape();
1893 auto sheetType = GetSheetType();
1894 BorderRadiusProperty borderRadius(sheetTheme->GetSheetRadius());
1895 CalculateSheetRadius(borderRadius);
1896 if (IsSheetBottom()) {
1897 // set 1px for avoiding doudble radius black lines.
1898 borderRadius.radiusBottomLeft = 1.0_px;
1899 borderRadius.radiusBottomRight = 1.0_px;
1900 }
1901 renderContext->UpdateBorderRadius(borderRadius);
1902 if (sheetTheme->IsOuterBorderEnable() && !sheetStyle.borderWidth.has_value()) {
1903 renderContext->UpdateOuterBorderRadius(borderRadius);
1904 }
1905 if (sheetType == SheetType::SHEET_POPUP) {
1906 std::string clipPath;
1907 clipPath = GetPopupStyleSheetClipPath(sheetSize, borderRadius);
1908 auto path = AceType::MakeRefPtr<Path>();
1909 path->SetValue(clipPath);
1910 path->SetBasicShapeType(BasicShapeType::PATH);
1911 renderContext->UpdateClipShape(path);
1912 }
1913 }
1914
1915 bool SheetPresentationPattern::IsWindowSizeChangedWithUndefinedReason(
1916 int32_t width, int32_t height, WindowSizeChangeReason type)
1917 {
1918 bool isWindowChanged = false;
1919 if (windowSize_.has_value()) {
1920 isWindowChanged = (type == WindowSizeChangeReason::UNDEFINED &&
1921 (windowSize_->Width() != width || windowSize_->Height() != height));
1922 }
1923 return isWindowChanged;
1924 }
1925
1926 void SheetPresentationPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
1927 {
1928 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet WindowSizeChangeReason type is: %{public}d", type);
1929 auto sheetType = GetSheetType();
1930 if ((type == WindowSizeChangeReason::ROTATION) &&
1931 ((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOMLANDSPACE))) {
1932 windowRotate_ = true;
1933 SetColumnMinSize(true);
1934 // Before rotation, reset to the initial mode sheet ratio of the current vertical or horizontal screen
1935 // It's actually a state where the soft keyboard is not pulled up
1936 if (isScrolling_) {
1937 ScrollTo(.0f);
1938 }
1939 }
1940 if (IsWindowSizeChangedWithUndefinedReason(width, height, type)) {
1941 windowChanged_ = true;
1942 }
1943 windowSize_ = SizeT<int32_t>(width, height);
1944 if (type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::DRAG ||
1945 type == WindowSizeChangeReason::RESIZE) {
1946 windowChanged_ = true;
1947 }
1948
1949 if (type == WindowSizeChangeReason::ROTATION && sheetType == SheetType::SHEET_CENTER) {
1950 auto recoverTask = [weak = WeakClaim(this), id = Container::CurrentId()] () {
1951 ContainerScope scope(id);
1952 auto pattern = weak.Upgrade();
1953 CHECK_NULL_VOID(pattern);
1954 pattern->RecoverHalfFoldOrAvoidStatus();
1955 };
1956 PostTask(recoverTask, "ArkUISheetHalfFoldStatusSwitch");
1957 }
1958
1959 auto host = GetHost();
1960 CHECK_NULL_VOID(host);
1961 auto pipelineContext = host->GetContext();
1962 CHECK_NULL_VOID(pipelineContext);
1963 UpdateSheetWhenSheetTypeChanged();
1964 auto windowManager = pipelineContext->GetWindowManager();
1965 if (windowManager && windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING) {
1966 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
1967 }
1968 }
1969
1970 void SheetPresentationPattern::TranslateTo(float height)
1971 {
1972 auto host = GetHost();
1973 CHECK_NULL_VOID(host);
1974 auto context = host->GetRenderContext();
1975 CHECK_NULL_VOID(context);
1976 context->UpdateTransformTranslate({ 0.0f, height, 0.0f });
1977 }
1978
1979 void SheetPresentationPattern::ScrollTo(float height)
1980 {
1981 // height = 0 or height > 0
1982 auto host = GetHost();
1983 CHECK_NULL_VOID(host);
1984 auto scroll = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
1985 CHECK_NULL_VOID(scroll);
1986 auto scrollPattern = scroll->GetPattern<ScrollPattern>();
1987 CHECK_NULL_VOID(scrollPattern);
1988 auto layoutProp = scrollPattern->GetLayoutProperty<ScrollLayoutProperty>();
1989 CHECK_NULL_VOID(layoutProp);
1990 auto geometryNode = scroll->GetGeometryNode();
1991 CHECK_NULL_VOID(geometryNode);
1992 // height > 0, Scroll will reduce height, and become scrolling.
1993 isScrolling_ = height > 0;
1994 SetColumnMinSize(!isScrolling_);
1995 if (!AdditionalScrollTo(scroll, height)) {
1996 scrollHeight_ = height;
1997 float maxScrollDecreaseHeight = scrollHeight_;
1998 float maxAvoidSize = keyboardHeight_ - (sheetType_ == SheetType::SHEET_CENTER ? height_ - centerHeight_ : 0.f);
1999 auto pipelineContext = host->GetContext();
2000 CHECK_NULL_VOID(pipelineContext);
2001 auto useCaretAvoidMode = pipelineContext->UsingCaretAvoidMode();
2002 /*
2003 * when the screen rotates from portrait to landscape, and the sheet needs to avoid caret twice,
2004 * there is a condition that, the caret position that does not exceed the height of sheet in portrait mode,
2005 * may be exceed the height of sheet in landscape mode. In that case,
2006 * the distance to avoid caret may exceed as well. To keep bindSheet display normally,
2007 * we need to obtain the minimum content height and then the avoidance is made.
2008 */
2009 if (useCaretAvoidMode && NonNegative(maxAvoidSize) && NonNegative(maxAvoidSize - sheetHeightUp_) &&
2010 maxScrollDecreaseHeight > maxAvoidSize - sheetHeightUp_) {
2011 maxScrollDecreaseHeight = maxAvoidSize - sheetHeightUp_;
2012 }
2013 layoutProp->UpdateUserDefinedIdealSize(CalcSize(std::nullopt,
2014 CalcLength(GetScrollHeight() - maxScrollDecreaseHeight)));
2015 auto curScrollOffset = (useCaretAvoidMode && Positive(height)) ? scrollPattern->GetTotalOffset() : 0.f;
2016 scrollPattern->UpdateCurrentOffset(-height + curScrollOffset, SCROLL_FROM_JUMP);
2017 }
2018 scroll->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2019 }
2020
2021 bool SheetPresentationPattern::AdditionalScrollTo(const RefPtr<FrameNode>& scroll, float height)
2022 {
2023 if (NonPositive(height)) {
2024 return false;
2025 }
2026 // If ScrollHeight is larger than childHeight
2027 // there will be a scene that is still larger than childHeight after reducing Scrollheight to moving sheet up
2028 // At this point, even if JumpToPosition is negative, the Scroll will still not to scroll
2029 auto buildContent = GetFirstFrameNodeOfBuilder();
2030 CHECK_NULL_RETURN(buildContent, false);
2031 auto scrollHeight = scroll->GetGeometryNode() ? scroll->GetGeometryNode()->GetFrameSize().Height() : .0f;
2032 auto host = GetHost();
2033 CHECK_NULL_RETURN(host, false);
2034 auto pipelineContext = host->GetContext();
2035 CHECK_NULL_RETURN(pipelineContext, false);
2036 auto useCaretAvoidMode = pipelineContext->UsingCaretAvoidMode();
2037 if (useCaretAvoidMode) {
2038 scrollHeight = GetScrollHeight();
2039 }
2040 auto childHeight = buildContent->GetGeometryNode() ? buildContent->GetGeometryNode()->GetFrameSize().Height() : .0f;
2041 if (scrollHeight <= childHeight) {
2042 return false;
2043 }
2044 auto layoutProp = scroll->GetLayoutProperty<ScrollLayoutProperty>();
2045 CHECK_NULL_RETURN(layoutProp, false);
2046 auto geometryNode = scroll->GetGeometryNode();
2047 CHECK_NULL_RETURN(geometryNode, false);
2048 auto scrollPattern = scroll->GetPattern<ScrollPattern>();
2049 CHECK_NULL_RETURN(scrollPattern, false);
2050 // Scroll first shrinks to the same size as childHeight, then reduces the height to allow it to scroll
2051 scrollHeight_ = scrollHeight - childHeight + height;
2052 layoutProp->UpdateUserDefinedIdealSize(
2053 CalcSize(std::nullopt, CalcLength(GetScrollHeight() - (scrollHeight - childHeight + height))));
2054 // And then scroll move the content with '-height' offset
2055 auto curScrollOffset = (useCaretAvoidMode && Positive(height)) ? scrollPattern->GetTotalOffset() : 0.f;
2056 scrollPattern->UpdateCurrentOffset(-height + curScrollOffset, SCROLL_FROM_JUMP);
2057 return true;
2058 }
2059
2060 float SheetPresentationPattern::GetFirstChildHeight() const
2061 {
2062 auto host = GetHost();
2063 CHECK_NULL_RETURN(host, 0.0f);
2064 auto firstChildNode = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
2065 CHECK_NULL_RETURN(firstChildNode, 0.0f);
2066 auto firstChildGeometryNode = firstChildNode->GetGeometryNode();
2067 CHECK_NULL_RETURN(firstChildGeometryNode, 0.0f);
2068 auto titleHeight = firstChildGeometryNode->GetFrameSize().Height();
2069 return titleHeight;
2070 }
2071
2072 void SheetPresentationPattern::SetColumnMinSize(bool reset)
2073 {
2074 auto buildContent = GetFirstFrameNodeOfBuilder();
2075 CHECK_NULL_VOID(buildContent);
2076 auto geometryNode = buildContent->GetGeometryNode();
2077 CHECK_NULL_VOID(geometryNode);
2078 auto props = buildContent->GetLayoutProperty<LayoutProperty>();
2079 CHECK_NULL_VOID(props);
2080 if (reset) {
2081 props->ResetCalcMinSize();
2082 return;
2083 }
2084 props->UpdateCalcMinSize(CalcSize(std::nullopt, CalcLength(builderHeight_)));
2085 }
2086
2087 void SheetPresentationPattern::CalculateSheetRadius(BorderRadiusProperty& sheetRadius)
2088 {
2089 auto host = GetHost();
2090 CHECK_NULL_VOID(host);
2091 auto geometryNode = host->GetGeometryNode();
2092 CHECK_NULL_VOID(geometryNode);
2093 auto sheetSize = geometryNode->GetFrameSize();
2094 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
2095 CHECK_NULL_VOID(layoutProperty);
2096 auto sheetStyle = layoutProperty->GetSheetStyleValue();
2097 if (sheetSize.IsPositive()) {
2098 CalculateAloneSheetRadius(sheetRadius.radiusTopLeft, sheetStyle.radius->radiusTopLeft);
2099 CalculateAloneSheetRadius(sheetRadius.radiusTopRight, sheetStyle.radius->radiusTopRight);
2100 CalculateAloneSheetRadius(sheetRadius.radiusBottomLeft, sheetStyle.radius->radiusBottomLeft);
2101 CalculateAloneSheetRadius(sheetRadius.radiusBottomRight, sheetStyle.radius->radiusBottomRight);
2102 }
2103 }
2104
2105 void SheetPresentationPattern::CalculateAloneSheetRadius(
2106 std::optional<Dimension>& sheetRadius, const std::optional<Dimension>& sheetStyleRadius)
2107 {
2108 auto host = GetHost();
2109 CHECK_NULL_VOID(host);
2110 auto geometryNode = host->GetGeometryNode();
2111 CHECK_NULL_VOID(geometryNode);
2112 auto sheetSize = geometryNode->GetFrameSize();
2113 float half = 0.5f;
2114 if (sheetStyleRadius.has_value() && GreatOrEqual(sheetStyleRadius->Value(), 0.0f)) {
2115 if (sheetStyleRadius->Unit() == DimensionUnit::PERCENT) {
2116 sheetRadius = Dimension(sheetStyleRadius->Value() * sheetSize.Width());
2117 } else {
2118 sheetRadius = sheetStyleRadius;
2119 }
2120 }
2121 // The maximum value of radius is half the width of the page.
2122 if (sheetSize.Width() * half < sheetRadius->ConvertToPx()) {
2123 sheetRadius = Dimension(sheetSize.Width() * half);
2124 }
2125 }
2126
2127 std::string SheetPresentationPattern::GetPopupStyleSheetClipPath(
2128 const SizeF& sheetSize, const BorderRadiusProperty& sheetRadius)
2129 {
2130 auto radiusTopLeft = sheetRadius.radiusTopLeft->ConvertToPx();
2131 auto radiusTopRight = sheetRadius.radiusTopRight->ConvertToPx();
2132 auto radiusBottomRight = sheetRadius.radiusBottomRight->ConvertToPx();
2133 auto radiusBottomLeft = sheetRadius.radiusBottomLeft->ConvertToPx();
2134 std::string path = MoveTo(0.0f, SHEET_ARROW_HEIGHT.ConvertToPx() + radiusTopLeft);
2135 path += ArcTo(radiusTopLeft, radiusTopLeft, 0.0f, 0, radiusTopLeft, SHEET_ARROW_HEIGHT.ConvertToPx());
2136 path +=
2137 LineTo(arrowOffset_.GetX() - ARROW_VERTICAL_P1_OFFSET_X.ConvertToPx(), SHEET_ARROW_HEIGHT.ConvertToPx()); // P1
2138 path += LineTo(arrowOffset_.GetX() - ARROW_VERTICAL_P2_OFFSET_X.ConvertToPx(),
2139 SHEET_ARROW_HEIGHT.ConvertToPx() - ARROW_VERTICAL_P2_OFFSET_Y.ConvertToPx()); // P2
2140 path += ArcTo(ARROW_RADIUS.ConvertToPx(), ARROW_RADIUS.ConvertToPx(), 0.0f, 0,
2141 arrowOffset_.GetX() + ARROW_VERTICAL_P4_OFFSET_X.ConvertToPx(),
2142 SHEET_ARROW_HEIGHT.ConvertToPx() - ARROW_VERTICAL_P4_OFFSET_Y.ConvertToPx()); // P4
2143 path +=
2144 LineTo(arrowOffset_.GetX() + ARROW_VERTICAL_P5_OFFSET_X.ConvertToPx(), SHEET_ARROW_HEIGHT.ConvertToPx()); // P5
2145 path += LineTo(sheetSize.Width() - radiusTopRight, SHEET_ARROW_HEIGHT.ConvertToPx());
2146 path += ArcTo(
2147 radiusTopRight, radiusTopRight, 0.0f, 0, sheetSize.Width(), SHEET_ARROW_HEIGHT.ConvertToPx() + radiusTopRight);
2148 path += LineTo(sheetSize.Width(), sheetSize.Height() - radiusBottomRight);
2149 path +=
2150 ArcTo(radiusBottomRight, radiusBottomRight, 0.0f, 0, sheetSize.Width() - radiusBottomRight, sheetSize.Height());
2151 path += LineTo(radiusBottomLeft, sheetSize.Height());
2152 path += ArcTo(radiusBottomLeft, radiusBottomLeft, 0.0f, 0, 0.0f, sheetSize.Height() - radiusBottomLeft);
2153 return path + "Z";
2154 }
2155
2156 std::string SheetPresentationPattern::GetCenterStyleSheetClipPath(SizeF sheetSize, Dimension sheetRadius)
2157 {
2158 std::string path = MoveTo(0.0f, sheetRadius.ConvertToPx());
2159 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetRadius.ConvertToPx(), 0.0f);
2160 path += LineTo(sheetSize.Width() - sheetRadius.ConvertToPx(), 0.0f);
2161 path += ArcTo(
2162 sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetSize.Width(), sheetRadius.ConvertToPx());
2163 path += LineTo(sheetSize.Width(), sheetSize.Height() - sheetRadius.ConvertToPx());
2164 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0,
2165 sheetSize.Width() - sheetRadius.ConvertToPx(), sheetSize.Height());
2166 path += LineTo(sheetRadius.ConvertToPx(), sheetSize.Height());
2167 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, 0.0f,
2168 sheetSize.Height() - sheetRadius.ConvertToPx());
2169 return path + "Z";
2170 }
2171
2172 std::string SheetPresentationPattern::GetBottomStyleSheetClipPath(SizeF sheetSize, Dimension sheetRadius)
2173 {
2174 std::string path = MoveTo(0.0f, sheetRadius.ConvertToPx());
2175 path += ArcTo(sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetRadius.ConvertToPx(), 0.0f);
2176 path += LineTo(sheetSize.Width() - sheetRadius.ConvertToPx(), 0.0f);
2177 path += ArcTo(
2178 sheetRadius.ConvertToPx(), sheetRadius.ConvertToPx(), 0.0f, 0, sheetSize.Width(), sheetRadius.ConvertToPx());
2179 path += LineTo(sheetSize.Width(), sheetSize.Height());
2180 path += LineTo(0.0f, sheetSize.Height());
2181 return path + "Z";
2182 }
2183
2184 std::string SheetPresentationPattern::MoveTo(double x, double y)
2185 {
2186 return "M" + std::to_string(x) + " " + std::to_string(y) + " ";
2187 }
2188
2189 std::string SheetPresentationPattern::LineTo(double x, double y)
2190 {
2191 return "L" + std::to_string(x) + " " + std::to_string(y) + " ";
2192 }
2193
2194 std::string SheetPresentationPattern::ArcTo(double rx, double ry, double rotation, int32_t arc_flag, double x, double y)
2195 {
2196 int32_t sweep_flag = 1;
2197 return "A" + std::to_string(rx) + " " + std::to_string(ry) + " " + std::to_string(rotation) + " " +
2198 std::to_string(arc_flag) + " " + std::to_string(sweep_flag) + " " + std::to_string(x) + " " +
2199 std::to_string(y) + " ";
2200 }
2201
2202 float SheetPresentationPattern::GetFitContentHeight()
2203 {
2204 auto sheetNode = GetHost();
2205 CHECK_NULL_RETURN(sheetNode, 0.0f);
2206 auto titleColumn = DynamicCast<FrameNode>(sheetNode->GetFirstChild());
2207 CHECK_NULL_RETURN(titleColumn, 0.0f);
2208 auto titleGeometryNode = titleColumn->GetGeometryNode();
2209 auto builderNode = GetFirstFrameNodeOfBuilder();
2210 CHECK_NULL_RETURN(builderNode, 0.0f);
2211 auto builderGeometryNode = builderNode->GetGeometryNode();
2212 return builderGeometryNode->GetMarginFrameSize().Height() + titleGeometryNode->GetFrameSize().Height();
2213 }
2214 void SheetPresentationPattern::ProcessColumnRect(float height)
2215 {
2216 const auto& overlayManager = GetOverlayManager();
2217 CHECK_NULL_VOID(overlayManager);
2218 auto maskNode = overlayManager->GetSheetMask(GetHost());
2219 if (maskNode && maskNode->GetTag() == V2::SHEET_WRAPPER_TAG) {
2220 return;
2221 }
2222 auto sheetNode = GetHost();
2223 CHECK_NULL_VOID(sheetNode);
2224 auto column = DynamicCast<FrameNode>(sheetNode->GetParent());
2225 CHECK_NULL_VOID(column);
2226 auto sheetType = GetSheetType();
2227 auto geometryNode = sheetNode->GetGeometryNode();
2228 CHECK_NULL_VOID(geometryNode);
2229 auto sheetSize = geometryNode->GetFrameSize();
2230 float sheetOffsetX = 0.0f;
2231 float sheetOffsetY = 0.0f;
2232 float sheetWidth = 0.0f;
2233 float sheetHeight = 0.0f;
2234 if (sheetType == SheetType::SHEET_POPUP) {
2235 sheetOffsetX = sheetOffsetX_;
2236 sheetWidth = sheetSize.Width();
2237 sheetOffsetY = sheetOffsetY_;
2238 sheetHeight = sheetSize.Height();
2239 } else if (sheetType == SheetType::SHEET_CENTER) {
2240 sheetOffsetX = sheetOffsetX_;
2241 sheetOffsetY = pageHeight_ - height;
2242 sheetWidth = sheetSize.Width();
2243 sheetHeight = sheetSize.Height();
2244 } else if ((sheetType == SheetType::SHEET_BOTTOM) || (sheetType == SheetType::SHEET_BOTTOM_FREE_WINDOW)) {
2245 sheetOffsetY = pageHeight_ - height;
2246 sheetWidth = sheetSize.Width();
2247 sheetOffsetX = sheetOffsetX_;
2248 sheetHeight = height;
2249 } else if (sheetType == SheetType::SHEET_BOTTOMLANDSPACE) {
2250 sheetOffsetX = sheetOffsetX_;
2251 sheetOffsetY = pageHeight_ - height;
2252 sheetWidth = sheetSize.Width();
2253 sheetHeight = height;
2254 }
2255 auto hub = column->GetEventHub<EventHub>();
2256 auto gestureHub = hub->GetOrCreateGestureEventHub();
2257 std::vector<DimensionRect> mouseResponseRegion;
2258 mouseResponseRegion.emplace_back(Dimension(sheetWidth), Dimension(sheetHeight),
2259 DimensionOffset(Dimension(sheetOffsetX), Dimension(sheetOffsetY)));
2260 gestureHub->SetMouseResponseRegion(mouseResponseRegion);
2261 gestureHub->SetResponseRegion(mouseResponseRegion);
2262 }
2263
2264 RefPtr<OverlayManager> SheetPresentationPattern::GetOverlayManager()
2265 {
2266 const auto& layoutProp = GetLayoutProperty<SheetPresentationProperty>();
2267 CHECK_NULL_RETURN(layoutProp, nullptr);
2268 auto showInPage = layoutProp->GetSheetStyleValue(SheetStyle()).showInPage.value_or(false);
2269 if (!showInPage) {
2270 return PipelineContext::GetCurrentContext()->GetOverlayManager();
2271 }
2272 auto host = GetHost();
2273 CHECK_NULL_RETURN(host, nullptr);
2274 auto sheetWrapper = host->GetParent();
2275 CHECK_NULL_RETURN(sheetWrapper, nullptr);
2276 auto node = AceType::DynamicCast<FrameNode>(sheetWrapper->GetParent());
2277 CHECK_NULL_RETURN(node, nullptr);
2278 RefPtr<OverlayManager> overlay;
2279 if (node->GetTag() == V2::PAGE_ETS_TAG) {
2280 auto pattern = node->GetPattern<PagePattern>();
2281 CHECK_NULL_RETURN(pattern, nullptr);
2282 overlay = pattern->GetOverlayManager();
2283 } else if (node->GetTag() == V2::NAVDESTINATION_VIEW_ETS_TAG) {
2284 auto pattern = node->GetPattern<NavDestinationPattern>();
2285 CHECK_NULL_RETURN(pattern, nullptr);
2286 overlay = pattern->GetOverlayManager();
2287 }
2288 if (!overlay) {
2289 auto overlayManager = overlayManager_.Upgrade();
2290 overlay = overlayManager;
2291 }
2292 return overlay;
2293 }
2294
2295 RefPtr<FrameNode> SheetPresentationPattern::GetFirstFrameNodeOfBuilder() const
2296 {
2297 auto host = GetHost();
2298 CHECK_NULL_RETURN(host, nullptr);
2299 auto scrollNode = host->GetChildAtIndex(1);
2300 CHECK_NULL_RETURN(scrollNode, nullptr);
2301 auto buildNode = scrollNode->GetChildAtIndex(0);
2302 CHECK_NULL_RETURN(buildNode, nullptr);
2303 return AceType::DynamicCast<FrameNode>(buildNode->GetFrameChildByIndex(0, true));
2304 }
2305
2306 void SheetPresentationPattern::GetBuilderInitHeight()
2307 {
2308 auto buildContent = GetFirstFrameNodeOfBuilder();
2309 CHECK_NULL_VOID(buildContent);
2310 auto geometryNode = buildContent->GetGeometryNode();
2311 CHECK_NULL_VOID(geometryNode);
2312 builderHeight_ = geometryNode->GetFrameSize().Height();
2313 }
2314
2315 RefPtr<FrameNode> SheetPresentationPattern::GetOverlayRoot()
2316 {
2317 const auto& layoutProp = GetLayoutProperty<SheetPresentationProperty>();
2318 CHECK_NULL_RETURN(layoutProp, nullptr);
2319 auto showInPage = layoutProp->GetSheetStyleValue(SheetStyle()).showInPage.value_or(false);
2320 if (!showInPage) {
2321 auto overlay = PipelineContext::GetCurrentContext()->GetOverlayManager();
2322 CHECK_NULL_RETURN(overlay, nullptr);
2323 return AceType::DynamicCast<FrameNode>(overlay->GetRootNode().Upgrade());
2324 }
2325 auto host = GetHost();
2326 CHECK_NULL_RETURN(host, nullptr);
2327 auto sheetWrapper = host->GetParent();
2328 CHECK_NULL_RETURN(sheetWrapper, nullptr);
2329 return AceType::DynamicCast<FrameNode>(sheetWrapper->GetParent());
2330 }
2331
2332 float SheetPresentationPattern::GetRootOffsetYToWindow()
2333 {
2334 const auto& layoutProp = GetLayoutProperty<SheetPresentationProperty>();
2335 CHECK_NULL_RETURN(layoutProp, .0f);
2336 const auto& showInPage = layoutProp->GetSheetStyleValue(SheetStyle()).showInPage.value_or(false);
2337 CHECK_NULL_RETURN(showInPage, .0f);
2338 const auto& overlayNode = GetOverlayRoot();
2339 CHECK_NULL_RETURN(overlayNode, .0f);
2340 auto parertOffset = overlayNode->GetOffsetRelativeToWindow();
2341 TAG_LOGD(AceLogTag::ACE_OVERLAY, "PageLevel Node's offset to window: %{public}s", parertOffset.ToString().c_str());
2342 return parertOffset.GetY();
2343 }
2344
2345 void SheetPresentationPattern::DumpAdvanceInfo()
2346 {
2347 DumpLog::GetInstance().AddDesc("------------------------------------------");
2348 DumpLog::GetInstance().AddDesc(
2349 "TargetId: " + std::to_string(static_cast<int32_t>(targetId_)) + " , TargetTag : " + targetTag_);
2350 DumpLog::GetInstance().AddDesc("------------ SheetPage Pattern : ");
2351 DumpLog::GetInstance().AddDesc(
2352 std::string("SheetType: ").append(std::to_string(static_cast<int32_t>(GetSheetType()))));
2353 DumpLog::GetInstance().AddDesc(std::string("SheetPage Node Height: ").append(std::to_string(centerHeight_)));
2354 DumpLog::GetInstance().AddDesc(
2355 std::string("Sheet Height [start from the bottom, KeyboardHeight = 0]: ").append(std::to_string(height_)));
2356 DumpLog::GetInstance().AddDesc(
2357 std::string("SheetMaxHeight [start from the bottom, pageHeight - sheetTopSafeArea]: ")
2358 .append(std::to_string(sheetMaxHeight_)));
2359 DumpLog::GetInstance().AddDesc(std::string("Page Height: ").append(std::to_string(pageHeight_)));
2360 DumpLog::GetInstance().AddDesc(
2361 std::string("StatusBar Height [current sheetType needed]: ").append(std::to_string(sheetTopSafeArea_)));
2362 DumpLog::GetInstance().AddDesc(std::string("PopupSheet OffsetX: ").append(std::to_string(sheetOffsetX_)));
2363 DumpLog::GetInstance().AddDesc(std::string("PopupSheet OffsetY: ").append(std::to_string(sheetOffsetY_)));
2364 DumpLog::GetInstance().AddDesc(std::string("SheetMaxWidth: ").append(std::to_string(sheetMaxWidth_)));
2365 DumpLog::GetInstance().AddDesc(std::string("FitContent Height: ").append(std::to_string(sheetFitContentHeight_)));
2366 DumpLog::GetInstance().AddDesc("SheetThemeType: " + sheetThemeType_);
2367 DumpLog::GetInstance().AddDesc(std::string("currentOffset: ").append(std::to_string(currentOffset_)));
2368 DumpLog::GetInstance().AddDesc("------------");
2369 DumpLog::GetInstance().AddDesc(
2370 std::string("Height ScrollTo [KeyboardHeight > 0, and is scrolling]: ").append(std::to_string(-scrollHeight_)));
2371 DumpLog::GetInstance().AddDesc(std::string("KeyboardHeight: ").append(std::to_string(keyboardHeight_)));
2372 DumpLog::GetInstance().AddDesc(std::string("is scrolling: ").append(isScrolling_ ? "true" : "false"));
2373 DumpLog::GetInstance().AddDesc(std::string("SheetHeightUp[sheet offset to move up when avoiding keyboard]: ")
2374 .append(std::to_string(sheetHeightUp_)));
2375 DumpLog::GetInstance().AddDesc("------------");
2376 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2377 CHECK_NULL_VOID(layoutProperty);
2378 auto sheetStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
2379 DumpLog::GetInstance().AddDesc(
2380 std::string("height: ").append(sheetStyle.sheetHeight.height.has_value() ?
2381 sheetStyle.sheetHeight.height->ToString() : "None"));
2382 DumpLog::GetInstance().AddDesc(
2383 ("sheetMode: ") + (sheetStyle.sheetHeight.sheetMode.has_value()
2384 ? std::to_string(static_cast<int32_t>(sheetStyle.sheetHeight.sheetMode.value()))
2385 : "None"));
2386 DumpLog::GetInstance().AddDesc(std::string("detents' Size: ").append(std::to_string(sheetStyle.detents.size())));
2387 DumpLog::GetInstance().AddDesc(std::string("IsShouldDismiss: ").append(shouldDismiss_ ? "true" : "false"));
2388 }
2389
2390 void SheetPresentationPattern::FireOnHeightDidChange()
2391 {
2392 auto height = 0.0f;
2393 if (!IsSheetBottomStyle()) {
2394 height = centerHeight_;
2395 } else {
2396 height = height_;
2397 }
2398 if (NearEqual(preDidHeight_, height)) {
2399 return;
2400 }
2401 OnHeightDidChange(height);
2402 preDidHeight_ = height;
2403 }
2404
2405 void SheetPresentationPattern::FireOnDetentsDidChange(float height)
2406 {
2407 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2408 CHECK_NULL_VOID(layoutProperty);
2409 auto sheetStyle = layoutProperty->GetSheetStyleValue();
2410 if (!IsSheetBottomStyle() || NearEqual(preDetentsHeight_, height) ||
2411 LessOrEqual(sheetStyle.detents.size(), 0)) {
2412 return;
2413 }
2414 OnDetentsDidChange(height);
2415 preDetentsHeight_ = height;
2416 }
2417
2418 void SheetPresentationPattern::FireOnWidthDidChange(RefPtr<FrameNode> sheetNode)
2419 {
2420 auto sheetGeo = sheetNode->GetGeometryNode();
2421 CHECK_NULL_VOID(sheetGeo);
2422 auto width = sheetGeo->GetFrameSize().Width();
2423 if (NearEqual(preWidth_, width)) {
2424 return;
2425 }
2426 onWidthDidChange(width);
2427 preWidth_ = width;
2428 }
2429
2430 void SheetPresentationPattern::FireOnTypeDidChange()
2431 {
2432 auto sheetType = sheetType_;
2433 if (sheetType == SheetType::SHEET_BOTTOMLANDSPACE || sheetType == SheetType::SHEET_BOTTOM_FREE_WINDOW) {
2434 sheetType = SheetType::SHEET_BOTTOM;
2435 }
2436 if (preType_ == sheetType) {
2437 return;
2438 }
2439 onTypeDidChange(sheetType);
2440 preType_ = sheetType;
2441 }
2442
2443 RefPtr<FrameNode> SheetPresentationPattern::GetScrollNode()
2444 {
2445 auto host = GetHost();
2446 CHECK_NULL_RETURN(host, nullptr);
2447 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
2448 CHECK_NULL_RETURN(scrollNode, nullptr);
2449 return scrollNode;
2450 }
2451
2452 bool SheetPresentationPattern::IsScrollOutOfBoundary()
2453 {
2454 auto scrollNode = GetScrollNode();
2455 CHECK_NULL_RETURN(scrollNode, false);
2456 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
2457 CHECK_NULL_RETURN(scrollPattern, false);
2458 return scrollPattern->OutBoundaryCallback();
2459 }
2460
2461 void SheetPresentationPattern::OnScrollStartRecursive(
2462 WeakPtr<NestableScrollContainer> child, float position, float velocity)
2463 {
2464 InitScrollProps();
2465 if (animation_ && isAnimationProcess_) {
2466 AnimationUtils::StopAnimation(animation_);
2467 isAnimationBreak_ = true;
2468 }
2469 currentOffset_ = 0.0f;
2470 isSheetNeedScroll_ = false;
2471 isDirectionUp_ = true;
2472 }
2473
2474 ScrollResult SheetPresentationPattern::HandleScroll(float scrollOffset, int32_t source, NestedState state,
2475 float velocity)
2476 {
2477 if (state == NestedState::CHILD_CHECK_OVER_SCROLL) {
2478 return {scrollOffset, true};
2479 }
2480 ScrollResult result = {0, true};
2481 if (GreatOrEqual(currentOffset_, 0.0) && (source == SCROLL_FROM_UPDATE) && !isSheetNeedScroll_) {
2482 isSheetNeedScroll_ = true;
2483 }
2484 if (!isSheetNeedScroll_ || IsScrollOutOfBoundary()) {
2485 return {scrollOffset, true};
2486 }
2487 ScrollState scrollState = source == SCROLL_FROM_ANIMATION ? ScrollState::FLING : ScrollState::SCROLL;
2488 if (state == NestedState::CHILD_SCROLL) {
2489 if (scrollState == ScrollState::SCROLL) {
2490 return HandleScrollWithSheet(scrollOffset);
2491 }
2492 if (isSheetPosChanged_) {
2493 HandleDragEnd(scrollOffset > 0 ? SHEET_VELOCITY_THRESHOLD : -SHEET_VELOCITY_THRESHOLD);
2494 isSheetPosChanged_ = false;
2495 }
2496 } else if (state == NestedState::CHILD_OVER_SCROLL) {
2497 isSheetNeedScroll_ = false;
2498 return {scrollOffset, true};
2499 }
2500 return result;
2501 }
2502
2503 ScrollResult SheetPresentationPattern::HandleScrollWithSheet(float scrollOffset)
2504 {
2505 ScrollResult result = {0, true};
2506 auto sheetType = GetSheetType();
2507 auto sheetDetentsSize = sheetDetentHeight_.size();
2508 if ((sheetType == SheetType::SHEET_POPUP) || (sheetDetentsSize == 0)) {
2509 isSheetNeedScroll_ = false;
2510 return {scrollOffset, true};
2511 }
2512
2513 auto currentHeightPos = GetSheetHeightBeforeDragUpdate();
2514 bool isDraggingUp = LessNotEqual(scrollOffset, 0.0f);
2515 bool isReachMaxSheetHeight = GreatOrEqual(currentHeightPos, GetMaxSheetHeightBeforeDragUpdate());
2516
2517 // When dragging up the sheet, and sheet height is larger than sheet content height,
2518 // the sheet height should be updated.
2519 // When dragging up the sheet, and sheet height is less than or equal to sheet content height,
2520 // the sheet content should scrolling.
2521 if ((NearZero(currentOffset_)) && isDraggingUp && isReachMaxSheetHeight) {
2522 isSheetNeedScroll_ = false;
2523 return {scrollOffset, true};
2524 }
2525
2526 // When dragging up the sheet, and sheet height is larger than max height,
2527 // should set the coefficient of friction.
2528 bool isExceedMaxSheetHeight =
2529 GreatNotEqual((currentHeightPos - currentOffset_), GetMaxSheetHeightBeforeDragUpdate());
2530 bool isNeedCalculateFriction = isExceedMaxSheetHeight && isDraggingUp;
2531 if (isNeedCalculateFriction && GreatNotEqual(sheetMaxHeight_, 0.0f)) {
2532 auto friction = CalculateFriction((currentHeightPos - currentOffset_) / sheetMaxHeight_);
2533 scrollOffset = scrollOffset * friction;
2534 }
2535
2536 auto host = GetHost();
2537 CHECK_NULL_RETURN(host, result);
2538 currentOffset_ = currentOffset_ + scrollOffset;
2539 auto pageHeight = GetPageHeightWithoutOffset();
2540 auto sheetOffsetInPage = pageHeight - currentHeightPos + currentOffset_;
2541 if (LessOrEqual(sheetOffsetInPage, pageHeight - sheetMaxHeight_)) {
2542 sheetOffsetInPage = pageHeight - sheetMaxHeight_;
2543 currentOffset_ = currentHeightPos - sheetMaxHeight_;
2544 }
2545 bool isNeedChangeScrollHeight = scrollSizeMode_ == ScrollSizeMode::CONTINUOUS && isDraggingUp;
2546 if (isNeedChangeScrollHeight) {
2547 ChangeScrollHeight(currentHeightPos - currentOffset_);
2548 }
2549 ProcessColumnRect(currentHeightPos - currentOffset_);
2550 auto renderContext = host->GetRenderContext();
2551 renderContext->UpdateTransformTranslate({ 0.0f, sheetOffsetInPage, 0.0f });
2552 isSheetPosChanged_ = NearZero(scrollOffset) ? false : true;
2553 if (IsSheetBottomStyle()) {
2554 OnHeightDidChange(height_ - currentOffset_ + sheetHeightUp_);
2555 }
2556 isSheetPosChanged_ = true;
2557 return result;
2558 }
2559
2560 void SheetPresentationPattern::OnScrollEndRecursive(const std::optional<float>& velocity)
2561 {
2562 if (isSheetPosChanged_) {
2563 HandleDragEnd(velocity.value_or(0.f));
2564 isSheetPosChanged_ = false;
2565 }
2566 }
2567
2568 bool SheetPresentationPattern::HandleScrollVelocity(float velocity, const RefPtr<NestableScrollContainer>& child)
2569 {
2570 if (isSheetPosChanged_) {
2571 HandleDragEnd(velocity);
2572 isSheetPosChanged_ = false;
2573 }
2574 // Use child edge effect
2575 if (!isSheetNeedScroll_) {
2576 return false;
2577 }
2578 return true;
2579 }
2580
2581 bool SheetPresentationPattern::IsTypeNeedAvoidAiBar()
2582 {
2583 auto overlay = GetOverlayManager();
2584 auto layoutProp = GetLayoutProperty<SheetPresentationProperty>();
2585 if (overlay && overlay->IsRootExpansive() &&
2586 layoutProp->GetSheetStyleValue(SheetStyle()).showInPage.value_or(false)) {
2587 return false;
2588 }
2589 return sheetType_ == SheetType::SHEET_BOTTOM || sheetType_ == SheetType::SHEET_BOTTOMLANDSPACE;
2590 }
2591
2592 void SheetPresentationPattern::IsNeedPlayTransition(const SheetStyle& inputStyle)
2593 {
2594 isPlayTransition_ = false;
2595 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2596 CHECK_NULL_VOID(layoutProperty);
2597 auto preStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
2598 if (preStyle.sheetHeight.height != inputStyle.sheetHeight.height) {
2599 isPlayTransition_ = true;
2600 return;
2601 }
2602 if (preStyle.detents != inputStyle.detents) {
2603 isPlayTransition_ = true;
2604 return;
2605 }
2606 if (preStyle.sheetHeight.sheetMode != inputStyle.sheetHeight.sheetMode) {
2607 isPlayTransition_ = true;
2608 return;
2609 }
2610 isPlayTransition_ = UpdateIndexByDetentSelection(inputStyle, false) || isPlayTransition_;
2611 }
2612
2613 bool SheetPresentationPattern::UpdateIndexByDetentSelection(const SheetStyle& inputStyle, bool isFirstTransition)
2614 {
2615 if (!inputStyle.detentSelection.has_value() || inputStyle.detents.size() == 0) {
2616 // when input detentSelection or detent selection is invalid
2617 return false;
2618 }
2619 auto selection = inputStyle.detentSelection.value();
2620 if ((selection.sheetMode.has_value() && selection.sheetMode.value() == NG::SheetMode::AUTO) ||
2621 (selection.height.has_value() && selection.height.value().IsNegative())) {
2622 return false;
2623 }
2624 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2625 CHECK_NULL_RETURN(layoutProperty, false);
2626 auto preStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
2627 if (!isFirstTransition && preStyle.detentSelection == inputStyle.detentSelection) {
2628 // only when sheet is first pulled up or pre-detents equal to current detents, otherwise false
2629 return false;
2630 }
2631 for (uint32_t index = 0; index < inputStyle.detents.size(); index++) {
2632 if (inputStyle.detents[index] == inputStyle.detentSelection.value()) {
2633 detentsFinalIndex_ = index;
2634 TAG_LOGI(AceLogTag::ACE_SHEET, "find detent selection is %u", index);
2635 return true;
2636 }
2637 }
2638 return false;
2639 }
2640
2641 void SheetPresentationPattern::OverlayDismissSheet()
2642 {
2643 auto overlayManager = GetOverlayManager();
2644 CHECK_NULL_VOID(overlayManager);
2645 overlayManager->DismissSheet();
2646 }
2647
2648 void SheetPresentationPattern::OverlaySheetSpringBack()
2649 {
2650 auto overlayManager = GetOverlayManager();
2651 CHECK_NULL_VOID(overlayManager);
2652 overlayManager->SheetSpringBack();
2653 }
2654
2655 void SheetPresentationPattern::MarkSheetPageNeedRender()
2656 {
2657 auto parentHost = GetHost()->GetParent();
2658 CHECK_NULL_VOID(parentHost);
2659 auto frameNode = AceType::DynamicCast<FrameNode>(parentHost);
2660 CHECK_NULL_VOID(frameNode);
2661 frameNode->MarkNeedRenderOnly();
2662 }
2663
2664 void SheetPresentationPattern::SetSheetOuterBorderWidth(
2665 const RefPtr<SheetTheme>& sheetTheme, const NG::SheetStyle& sheetStyle)
2666 {
2667 auto host = GetHost();
2668 CHECK_NULL_VOID(host);
2669 auto renderContext = host->GetRenderContext();
2670 CHECK_NULL_VOID(renderContext);
2671 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
2672 CHECK_NULL_VOID(layoutProperty);
2673 auto sheetType = GetSheetType();
2674 if (sheetTheme->IsOuterBorderEnable() && !sheetStyle.borderWidth.has_value()) {
2675 BorderWidthProperty borderWidth;
2676 BorderWidthProperty outBorderWidth;
2677 BorderColorProperty borderColor;
2678 BorderColorProperty outBorderColor;
2679 borderWidth.SetBorderWidth(0.0_vp);
2680 outBorderWidth.SetBorderWidth(0.0_vp);
2681 if (sheetType != SheetType::SHEET_POPUP) {
2682 borderColor.SetColor(sheetTheme->GetSheetInnerBorderColor());
2683 outBorderColor.SetColor(sheetTheme->GetSheetOuterBorderColor());
2684 renderContext->UpdateOuterBorderColor(outBorderColor);
2685 renderContext->UpdateBorderColor(borderColor);
2686 if (sheetType == SheetType::SHEET_CENTER) {
2687 borderWidth.SetBorderWidth(sheetTheme->GetSheetInnerBorderWidth());
2688 outBorderWidth.SetBorderWidth(sheetTheme->GetSheetOuterBorderWidth());
2689 } else {
2690 borderWidth.leftDimen = sheetTheme->GetSheetInnerBorderWidth();
2691 borderWidth.topDimen = sheetTheme->GetSheetInnerBorderWidth();
2692 borderWidth.rightDimen = sheetTheme->GetSheetInnerBorderWidth();
2693 outBorderWidth.leftDimen = sheetTheme->GetSheetOuterBorderWidth();
2694 outBorderWidth.topDimen = sheetTheme->GetSheetOuterBorderWidth();
2695 outBorderWidth.rightDimen = sheetTheme->GetSheetOuterBorderWidth();
2696 }
2697 }
2698 layoutProperty->UpdateBorderWidth(borderWidth);
2699 renderContext->UpdateBorderWidth(borderWidth);
2700 layoutProperty->UpdateOuterBorderWidth(outBorderWidth);
2701 renderContext->UpdateOuterBorderWidth(outBorderWidth);
2702 }
2703 }
2704
2705 void SheetPresentationPattern::AvoidKeyboardBySheetMode(bool forceAvoid)
2706 {
2707 if (keyboardAvoidMode_ == SheetKeyboardAvoidMode::NONE) {
2708 TAG_LOGD(AceLogTag::ACE_SHEET, "Sheet will not avoid keyboard.");
2709 return;
2710 }
2711 auto host = GetHost();
2712 CHECK_NULL_VOID(host);
2713 auto pipelineContext = host->GetContext();
2714 CHECK_NULL_VOID(pipelineContext);
2715 auto manager = pipelineContext->GetSafeAreaManager();
2716 if (keyboardHeight_ == manager->GetKeyboardInset().Length() && !forceAvoid) {
2717 return;
2718 }
2719 keyboardHeight_ = manager->GetKeyboardInset().Length();
2720
2721 if (isDismissProcess_) {
2722 TAG_LOGD(AceLogTag::ACE_SHEET,
2723 "The sheet will disappear, so there's no need to handle canceling keyboard avoidance here.");
2724 return;
2725 }
2726
2727 // 1.handle non upward logic: avoidKeyboardMode::RESIZE_ONLY
2728 if (AvoidKeyboardBeforeTranslate()) {
2729 return;
2730 }
2731
2732 // 2.handle upward logic
2733 CHECK_NULL_VOID(host->GetFocusHub());
2734 // When bindSheet lift height exceed the max height, hightUp = the remaining height that needs to scroll,
2735 // otherwise, hightUp = the height to be lifted up
2736 auto heightUp = host->GetFocusHub()->IsCurrentFocus() ? GetSheetHeightChange() : 0.0f;
2737 sheetHeightUp_ = heightUp;
2738 TAG_LOGD(AceLogTag::ACE_SHEET, "To avoid Keyboard, sheet needs to deal with %{public}f height.", heightUp);
2739 auto offset = pageHeight_ - height_ - heightUp;
2740 auto renderContext = host->GetRenderContext();
2741
2742 // when bindSheet height exceed the max height, lift it up to the maxHeight,
2743 // otherwise, lift it up to show input area
2744 if (isScrolling_) {
2745 if (NearZero(heightUp)) {
2746 // scroll needs to reset first when keyboard is down.
2747 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
2748 } else {
2749 sheetHeightUp_ = pageHeight_ - (SHEET_BLANK_MINI_HEIGHT.ConvertToPx() + sheetTopSafeArea_) - height_;
2750 // sheet is raised to the top first
2751 renderContext->UpdateTransformTranslate(
2752 { 0.0f, SHEET_BLANK_MINI_HEIGHT.ConvertToPx() + sheetTopSafeArea_, 0.0f });
2753 }
2754 } else {
2755 // offset: translate endpoint, calculated from top
2756 renderContext->UpdateTransformTranslate({ 0.0f, offset, 0.0f });
2757 }
2758
2759 // 3.deal with left height, scroll or resize
2760 if (isScrolling_) {
2761 AvoidKeyboardAfterTranslate(heightUp);
2762 }
2763
2764 if (IsSheetBottomStyle()) {
2765 OnHeightDidChange(height_ + sheetHeightUp_);
2766 }
2767 }
2768
2769 bool SheetPresentationPattern::AvoidKeyboardBeforeTranslate()
2770 {
2771 if (keyboardAvoidMode_ == SheetKeyboardAvoidMode::RESIZE_ONLY) {
2772 // resize bindSheet need to keep safe distance from keyboard
2773 auto distanceFromBottom = sheetType_ == SheetType::SHEET_CENTER ? height_ - centerHeight_ : 0.0f;
2774 DecreaseScrollHeightInSheet(keyboardHeight_ == 0 ? 0.0f : keyboardHeight_ - distanceFromBottom);
2775 return true;
2776 }
2777 return false;
2778 }
2779
2780 void SheetPresentationPattern::AvoidKeyboardAfterTranslate(float height)
2781 {
2782 switch (keyboardAvoidMode_) {
2783 case SheetKeyboardAvoidMode::NONE:
2784 case SheetKeyboardAvoidMode::RESIZE_ONLY:
2785 break;
2786 case SheetKeyboardAvoidMode::TRANSLATE_AND_RESIZE:
2787 // resize bindSheet need to keep safe distance from keyboard
2788 DecreaseScrollHeightInSheet(keyboardHeight_ == 0 ? 0.0f : height);
2789 break;
2790 case SheetKeyboardAvoidMode::TRANSLATE_AND_SCROLL:
2791 ScrollTo(height);
2792 break;
2793 default:
2794 TAG_LOGW(AceLogTag::ACE_SHEET, "Invalid keyboard avoid mode %{public}d", keyboardAvoidMode_);
2795 break;
2796 }
2797 }
2798
2799 void SheetPresentationPattern::DecreaseScrollHeightInSheet(float decreaseHeight)
2800 {
2801 auto host = GetHost();
2802 CHECK_NULL_VOID(host);
2803 auto scroll = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
2804 CHECK_NULL_VOID(scroll);
2805 auto layoutProp = scroll->GetLayoutProperty<ScrollLayoutProperty>();
2806 CHECK_NULL_VOID(layoutProp);
2807
2808 // height > 0, Scroll will reduce height, and need to set isScrolling true
2809 isScrolling_ = (decreaseHeight > 0);
2810
2811 TAG_LOGD(AceLogTag::ACE_SHEET, "To avoid Keyboard, Scroll Height reduces by height %{public}f.", decreaseHeight);
2812 layoutProp->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(GetScrollHeight() - decreaseHeight)));
2813 resizeDecreasedHeight_ = decreaseHeight;
2814 scroll->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
2815 }
2816
2817 bool SheetPresentationPattern::IsResizeWhenAvoidKeyboard()
2818 {
2819 return keyboardAvoidMode_ == SheetKeyboardAvoidMode::TRANSLATE_AND_RESIZE ||
2820 keyboardAvoidMode_ == SheetKeyboardAvoidMode::RESIZE_ONLY;
2821 }
2822
2823 void SheetPresentationPattern::ResetClipShape()
2824 {
2825 // need reset clip path,when system clip path change to user defined
2826 auto host = GetHost();
2827 CHECK_NULL_VOID(host);
2828 auto renderContext = host->GetRenderContext();
2829 CHECK_NULL_VOID(renderContext);
2830 renderContext->UpdateClipShape(nullptr);
2831 renderContext->ResetClipShape();
2832 }
2833
2834 void SheetPresentationPattern::UpdateSheetWhenSheetTypeChanged()
2835 {
2836 auto sheetType = GetSheetType();
2837 if (sheetType_ != sheetType) {
2838 // It can only be MarkOuterBorder When the SheetType switches and the sheetType_ was SHEET_POPUP
2839 if (sheetType_ == SheetType::SHEET_POPUP) {
2840 MarkSheetPageNeedRender();
2841 }
2842 sheetType_ = sheetType;
2843 SetSheetBorderWidth();
2844 }
2845 }
2846
2847 bool SheetPresentationPattern::IsCurSheetNeedHalfFoldHover()
2848 {
2849 auto host = GetHost();
2850 CHECK_NULL_RETURN(host, false);
2851 auto pipeline = host->GetContext();
2852 CHECK_NULL_RETURN(pipeline, false);
2853 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
2854 CHECK_NULL_RETURN(sheetTheme, false);
2855 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2856 CHECK_NULL_RETURN(layoutProperty, false);
2857 auto sheetStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
2858 auto enableHoverMode = sheetStyle.enableHoverMode.value_or(false);
2859 bool isHoverMode = enableHoverMode ? pipeline->IsHalfFoldHoverStatus() : false;
2860 return isHoverMode && GetSheetType() == SheetType::SHEET_CENTER;
2861 }
2862
2863 void SheetPresentationPattern::GetCurrentScrollHeight()
2864 {
2865 auto host = GetHost();
2866 CHECK_NULL_VOID(host);
2867 auto scrollNode = DynamicCast<FrameNode>(host->GetChildAtIndex(1));
2868 CHECK_NULL_VOID(scrollNode);
2869 auto scrollPattern = scrollNode->GetPattern<ScrollPattern>();
2870 CHECK_NULL_VOID(scrollPattern);
2871 auto curOffset = scrollPattern->GetTotalOffset();
2872 if (NearEqual(scrollHeight_, curOffset)) {
2873 return;
2874 }
2875 TAG_LOGD(AceLogTag::ACE_SHEET, "scroll height changed because of user scrolling, %{public}f", curOffset);
2876 scrollHeight_ = curOffset;
2877 }
2878
2879 void SheetPresentationPattern::InitFoldCreaseRegion()
2880 {
2881 auto host = GetHost();
2882 CHECK_NULL_VOID(host);
2883 auto pipeline = host->GetContext();
2884 CHECK_NULL_VOID(pipeline);
2885 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
2886 CHECK_NULL_VOID(sheetTheme);
2887 auto layoutProperty = GetLayoutProperty<SheetPresentationProperty>();
2888 CHECK_NULL_VOID(layoutProperty);
2889 auto sheetStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
2890 auto enableHoverMode = sheetStyle.enableHoverMode.value_or(false);
2891 if (!enableHoverMode || !currentFoldCreaseRegion_.empty()) {
2892 return;
2893 }
2894 auto container = Container::Current();
2895 CHECK_NULL_VOID(container);
2896 auto displayInfo = container->GetDisplayInfo();
2897 CHECK_NULL_VOID(displayInfo);
2898 currentFoldCreaseRegion_ = displayInfo->GetCurrentFoldCreaseRegion();
2899 }
2900
2901 Rect SheetPresentationPattern::GetFoldScreenRect() const
2902 {
2903 if (currentFoldCreaseRegion_.empty()) {
2904 TAG_LOGW(AceLogTag::ACE_SHEET, "FoldCreaseRegion is invalid.");
2905 return Rect();
2906 }
2907 return currentFoldCreaseRegion_.front();
2908 }
2909
2910 void SheetPresentationPattern::FireHoverModeChangeCallback()
2911 {
2912 auto host = GetHost();
2913 CHECK_NULL_VOID(host);
2914 auto pipeline = host->GetContext();
2915 CHECK_NULL_VOID(pipeline);
2916 if (!IsCurSheetNeedHalfFoldHover()) {
2917 TAG_LOGD(AceLogTag::ACE_SHEET, "halfFoldHoverStatus: %{public}d, Sheet is not half folded.",
2918 pipeline->IsHalfFoldHoverStatus());
2919 return;
2920 }
2921 OnHeightDidChange(centerHeight_);
2922 }
2923
2924 void SheetPresentationPattern::RecoverHalfFoldOrAvoidStatus()
2925 {
2926 TAG_LOGD(AceLogTag::ACE_SHEET, "recover half fold status because of window rotate");
2927 auto host = GetHost();
2928 CHECK_NULL_VOID(host);
2929 auto pipeline = host->GetContext();
2930 CHECK_NULL_VOID(pipeline);
2931 if (IsCurSheetNeedHalfFoldHover()) {
2932 RecoverAvoidKeyboardStatus();
2933 } else {
2934 AvoidSafeArea(true);
2935 }
2936 }
2937
2938 void SheetPresentationPattern::RecoverAvoidKeyboardStatus()
2939 {
2940 RecoverScrollOrResizeAvoidStatus();
2941 sheetHeightUp_ = 0.f;
2942 OnHeightDidChange(centerHeight_);
2943 }
2944
2945 void SheetPresentationPattern::RecoverScrollOrResizeAvoidStatus()
2946 {
2947 auto host = GetHost();
2948 CHECK_NULL_VOID(host);
2949 auto scroll = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(1));
2950 CHECK_NULL_VOID(scroll);
2951 auto layoutProp = scroll->GetLayoutProperty<ScrollLayoutProperty>();
2952 CHECK_NULL_VOID(layoutProp);
2953 layoutProp->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(GetScrollHeight())));
2954 resizeDecreasedHeight_ = 0.f;
2955 scrollHeight_ = 0.f;
2956 ScrollTo(0.f);
2957 isScrolling_ = false;
2958 }
2959 } // namespace OHOS::Ace::NG
2960