1 /*
2 * Copyright (c) 2025 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/sheet/side/sheet_side_object.h"
17
18 #include "ui/base/ace_type.h"
19 #include "ui/base/utils/utils.h"
20
21 #include "base/geometry/dimension.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.h"
24 #include "core/components_ng/pattern/overlay/overlay_manager.h"
25 #include "core/components_ng/pattern/overlay/sheet_manager.h"
26 #include "core/components_ng/pattern/overlay/sheet_presentation_pattern.h"
27 #include "core/components_ng/pattern/scroll/scroll_layout_property.h"
28 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
29 #include "core/components_ng/pattern/text_field/text_field_manager.h"
30
31 namespace OHOS::Ace::NG {
32
PostProcessBorderWidth(const NG::BorderWidthProperty & borderWidth)33 NG::BorderWidthProperty SheetSideObject::PostProcessBorderWidth(const NG::BorderWidthProperty& borderWidth)
34 {
35 NG::BorderWidthProperty result = borderWidth;
36 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
37 result.leftDimen = 0.0_vp;
38 } else {
39 result.rightDimen = 0.0_vp;
40 }
41 return result;
42 }
43
DirtyLayoutProcess(const RefPtr<LayoutAlgorithmWrapper> & layoutAlgorithmWrapper)44 void SheetSideObject::DirtyLayoutProcess(const RefPtr<LayoutAlgorithmWrapper>& layoutAlgorithmWrapper)
45 {
46 auto pattern = GetPattern();
47 CHECK_NULL_VOID(pattern);
48 auto sideSheetLayoutAlgorithm =
49 AceType::DynamicCast<SheetPresentationSideLayoutAlgorithm>(layoutAlgorithmWrapper->GetLayoutAlgorithm());
50 CHECK_NULL_VOID(sideSheetLayoutAlgorithm);
51 if (sideSheetLayoutAlgorithm->GetSideSheetMaxWidth() > 0) {
52 sheetMaxWidth_ = sideSheetLayoutAlgorithm->GetSideSheetMaxWidth();
53 sheetWidth_ = sideSheetLayoutAlgorithm->GetSideSheetWidth();
54 pattern->SetSheetMaxHeight(sideSheetLayoutAlgorithm->GetSideSheetMaxHeight());
55 }
56 if (GreatNotEqual(sideSheetLayoutAlgorithm->GetSheetHeight(), 0.0f)) {
57 SetSheetHeight(sideSheetLayoutAlgorithm->GetSheetHeight());
58 }
59 UpdateDragBarStatus();
60 UpdateSidePosition();
61 }
62
UpdateDragBarStatus()63 void SheetSideObject::UpdateDragBarStatus()
64 {
65 auto pattern = GetPattern();
66 CHECK_NULL_VOID(pattern);
67 auto host = pattern->GetHost();
68 CHECK_NULL_VOID(host);
69
70 auto sheetPattern = host->GetPattern<SheetPresentationPattern>();
71 CHECK_NULL_VOID(sheetPattern);
72 auto sheetDragBar = sheetPattern->GetDragBarNode();
73 CHECK_NULL_VOID(sheetDragBar);
74 auto dragBarLayoutProperty = sheetDragBar->GetLayoutProperty();
75 CHECK_NULL_VOID(dragBarLayoutProperty);
76
77 dragBarLayoutProperty->UpdateVisibility(VisibleType::INVISIBLE);
78 sheetDragBar->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
79 }
80
UpdateSidePosition()81 void SheetSideObject::UpdateSidePosition()
82 {
83 auto sheetPattern = GetPattern();
84 CHECK_NULL_VOID(sheetPattern);
85 auto sheetNode = sheetPattern->GetHost();
86 CHECK_NULL_VOID(sheetNode);
87 auto context = sheetNode->GetRenderContext();
88 CHECK_NULL_VOID(context);
89
90 if (!sheetPattern->IsOnAppearing()
91 && !sheetPattern->IsOnDisappearing() && !sheetPattern->IsDragging()) {
92 sheetPattern->FireOnWidthDidChange();
93 FireHeightDidChange();
94 bool isRTL = AceApplicationInfo::GetInstance().IsRightToLeft();
95 if (!isRTL) {
96 context->UpdateTransformTranslate({ sheetMaxWidth_ - sheetWidth_, 0.0f, 0.0f });
97 } else {
98 context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
99 }
100 }
101 }
102
GetSheetTransitionCurve(float dragVelocity) const103 RefPtr<InterpolatingSpring> SheetSideObject::GetSheetTransitionCurve(float dragVelocity) const
104 {
105 return AceType::MakeRefPtr<InterpolatingSpring>(
106 0.0f, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
107 }
108
GetSheetTransitionFinishEvent(bool isTransitionIn)109 std::function<void()> SheetSideObject::GetSheetTransitionFinishEvent(bool isTransitionIn)
110 {
111 const std::function<void()> event = [weak = pattern_, isTransitionIn]() {
112 auto pattern = weak.Upgrade();
113 CHECK_NULL_VOID(pattern);
114 if (isTransitionIn) {
115 if (!pattern->GetAnimationBreak()) {
116 pattern->SetAnimationProcess(false);
117 pattern->GetSheetObject()->SetCurrentOffset(0.0f);
118 } else {
119 pattern->SetAnimationBreak(false);
120 }
121 pattern->AvoidAiBar();
122 pattern->SetSpringBack(false);
123 } else {
124 pattern->SetAnimationProcess(false);
125 const auto& overlayManager = pattern->GetOverlayManager();
126 CHECK_NULL_VOID(overlayManager);
127 auto host = pattern->GetHost();
128 CHECK_NULL_VOID(host);
129 overlayManager->FireAutoSave(host);
130 pattern->OnDisappear();
131 overlayManager->RemoveSheet(host);
132 pattern->FireCallback("false");
133 }
134 };
135 return event;
136 }
137
GetSheetAnimationEvent(bool isTransitionIn,float offset)138 std::function<void()> SheetSideObject::GetSheetAnimationEvent(bool isTransitionIn, float offset)
139 {
140 auto sheetPattern = GetPattern();
141 CHECK_NULL_RETURN(sheetPattern, nullptr);
142 auto sheetNode = sheetPattern->GetHost();
143 CHECK_NULL_RETURN(sheetNode, nullptr);
144 auto context = sheetNode->GetRenderContext();
145 CHECK_NULL_RETURN(context, nullptr);
146
147 std::function<void()> event;
148 if (isTransitionIn) {
149 event = [weak = WeakClaim(this)]() {
150 auto sheetObject = weak.Upgrade();
151 CHECK_NULL_VOID(sheetObject);
152 sheetObject->TransformTranslateEnter();
153 };
154 } else {
155 event = [context, weak = pattern_, objWeak = WeakClaim(this)]() {
156 auto pattern = weak.Upgrade();
157 CHECK_NULL_VOID(pattern);
158 auto sheetObject = objWeak.Upgrade();
159 CHECK_NULL_VOID(sheetObject);
160 sheetObject->TransformTranslateExit();
161 pattern->DismissSheetShadow(context);
162 };
163 }
164 return event;
165 }
166
167
ClipSheetNode()168 void SheetSideObject::ClipSheetNode()
169 {
170 auto pattern = GetPattern();
171 CHECK_NULL_VOID(pattern);
172 auto host = pattern->GetHost();
173 CHECK_NULL_VOID(host);
174 auto geometryNode = host->GetGeometryNode();
175 CHECK_NULL_VOID(geometryNode);
176 auto pipeline = PipelineContext::GetCurrentContext();
177 CHECK_NULL_VOID(pipeline);
178 auto sheetTheme = pipeline->GetTheme<SheetTheme>();
179 CHECK_NULL_VOID(sheetTheme);
180 auto renderContext = host->GetRenderContext();
181 CHECK_NULL_VOID(renderContext);
182 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
183 CHECK_NULL_VOID(layoutProperty);
184 auto sheetStyle = layoutProperty->GetSheetStyleValue();
185 pattern->ResetClipShape();
186 BorderRadiusProperty borderRadius(sheetTheme->GetSheetSideRadius());
187 pattern->CalculateSheetRadius(borderRadius);
188 // set 1px for avoiding doudble radius black lines.
189 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
190 borderRadius.radiusTopLeft = 1.0_px;
191 borderRadius.radiusBottomLeft = 1.0_px;
192 } else {
193 borderRadius.radiusTopRight = 1.0_px;
194 borderRadius.radiusBottomRight = 1.0_px;
195 }
196 renderContext->UpdateBorderRadius(borderRadius);
197 // innerBorder need to adapt
198 }
199
InitAnimationForOverlay(bool isTransitionIn,bool isFirstTransition)200 void SheetSideObject::InitAnimationForOverlay(bool isTransitionIn, bool isFirstTransition)
201 {
202 auto sheetPattern = GetPattern();
203 CHECK_NULL_VOID(sheetPattern);
204 auto sheetNode = sheetPattern->GetHost();
205 CHECK_NULL_VOID(sheetNode);
206 auto sheetParent = AceType::DynamicCast<FrameNode>(sheetNode->GetParent());
207 CHECK_NULL_VOID(sheetParent);
208 if (isTransitionIn) {
209 if (isFirstTransition) {
210 TransformTranslateExit();
211 sheetPattern->GetBuilderInitHeight();
212 }
213 sheetPattern->FireOnTypeDidChange();
214 FireHeightDidChange();
215 ACE_SCOPED_TRACE("Side Sheet starts the entrance animation");
216 }
217 }
218
SetFinishEventForAnimationOption(AnimationOption & option,bool isTransitionIn,bool isFirstTransition)219 void SheetSideObject::SetFinishEventForAnimationOption(
220 AnimationOption& option, bool isTransitionIn, bool isFirstTransition)
221 {
222 auto sheetPattern = GetPattern();
223 CHECK_NULL_VOID(sheetPattern);
224 auto sheetNode = sheetPattern->GetHost();
225 CHECK_NULL_VOID(sheetNode);
226 if (isTransitionIn) {
227 option.SetOnFinishEvent(
228 [sheetWK = WeakClaim(RawPtr(sheetNode)), isFirst = isFirstTransition] {
229 auto sheetNode = sheetWK.Upgrade();
230 CHECK_NULL_VOID(sheetNode);
231 auto pattern = sheetNode->GetPattern<SheetPresentationPattern>();
232 CHECK_NULL_VOID(pattern);
233 pattern->OnAppear();
234 pattern->AvoidAiBar();
235 pattern->FireOnWidthDidChange();
236 });
237 } else {
238 option.SetOnFinishEvent(
239 [sheetWK = WeakClaim(RawPtr(sheetNode))] {
240 auto sheet = sheetWK.Upgrade();
241 CHECK_NULL_VOID(sheet);
242 auto pattern = sheet->GetPattern<SheetPresentationPattern>();
243 CHECK_NULL_VOID(pattern);
244 auto overlayManager = pattern->GetOverlayManager();
245 CHECK_NULL_VOID(overlayManager);
246 pattern->OnDisappear();
247 overlayManager->FireAutoSave(sheet);
248 overlayManager->RemoveSheet(sheet);
249 });
250 }
251 }
252
GetAnimationOptionForOverlay(bool isTransitionIn,bool isFirstTransition)253 AnimationOption SheetSideObject::GetAnimationOptionForOverlay(bool isTransitionIn, bool isFirstTransition)
254 {
255 AnimationOption option;
256 auto sheetPattern = GetPattern();
257 CHECK_NULL_RETURN(sheetPattern, option);
258 const RefPtr<InterpolatingSpring> curve =
259 AceType::MakeRefPtr<InterpolatingSpring>(0.0f, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
260 option.SetCurve(curve);
261 option.SetFillMode(FillMode::FORWARDS);
262 option.SetDuration(SHEET_ANIMATION_DURATION);
263 SetFinishEventForAnimationOption(option, isTransitionIn, isFirstTransition);
264 return option;
265 }
266
TransformTranslateEnter()267 void SheetSideObject::TransformTranslateEnter()
268 {
269 auto sheetPattern = GetPattern();
270 CHECK_NULL_VOID(sheetPattern);
271 auto sheetNode = sheetPattern->GetHost();
272 CHECK_NULL_VOID(sheetNode);
273 auto context = sheetNode->GetRenderContext();
274 CHECK_NULL_VOID(context);
275 bool isRTL = AceApplicationInfo::GetInstance().IsRightToLeft();
276 if (isRTL) {
277 context->UpdateTransformTranslate({ 0.0f, 0.0f, 0.0f });
278 } else {
279 context->UpdateTransformTranslate({ sheetMaxWidth_ - sheetWidth_, 0.0f, 0.0f });
280 }
281 }
282
TransformTranslateExit()283 void SheetSideObject::TransformTranslateExit()
284 {
285 auto sheetPattern = GetPattern();
286 CHECK_NULL_VOID(sheetPattern);
287 auto sheetNode = sheetPattern->GetHost();
288 CHECK_NULL_VOID(sheetNode);
289 auto context = sheetNode->GetRenderContext();
290 CHECK_NULL_VOID(context);
291 bool isRTL = AceApplicationInfo::GetInstance().IsRightToLeft();
292 if (isRTL) {
293 context->UpdateTransformTranslate({ -sheetWidth_, 0.0f, 0.0f });
294 } else {
295 context->UpdateTransformTranslate({ sheetMaxWidth_, 0.0f, 0.0f });
296 }
297 }
298
GetAnimationPropertyCallForOverlay(bool isTransitionIn)299 std::function<void()> SheetSideObject::GetAnimationPropertyCallForOverlay(bool isTransitionIn)
300 {
301 auto sheetPattern = GetPattern();
302 CHECK_NULL_RETURN(sheetPattern, nullptr);
303 auto sheetNode = sheetPattern->GetHost();
304 CHECK_NULL_RETURN(sheetNode, nullptr);
305 auto context = sheetNode->GetRenderContext();
306 CHECK_NULL_RETURN(context, nullptr);
307
308 std::function<void()> event;
309 if (isTransitionIn) {
310 event = [weak = WeakClaim(this)]() {
311 auto sheetObject = weak.Upgrade();
312 CHECK_NULL_VOID(sheetObject);
313 sheetObject->TransformTranslateEnter();
314 };
315 } else {
316 event = [context, weak = pattern_, objWeak = WeakClaim(this)]() {
317 auto pattern = weak.Upgrade();
318 CHECK_NULL_VOID(pattern);
319 auto sheetObject = objWeak.Upgrade();
320 CHECK_NULL_VOID(sheetObject);
321 sheetObject->TransformTranslateExit();
322 pattern->DismissSheetShadow(context);
323 };
324 }
325 return event;
326 }
327
OnLanguageConfigurationUpdate()328 void SheetSideObject::OnLanguageConfigurationUpdate()
329 {
330 auto sheetPattern = GetPattern();
331 CHECK_NULL_VOID(sheetPattern);
332 sheetPattern->CheckLocalized();
333 CHECK_NULL_VOID(sheetPattern->GetShowState());
334 CHECK_NULL_VOID(!sheetPattern->GetIsPlayTransition());
335 TransformTranslateEnter();
336 }
337
GetSheetSafeAreaPadding() const338 PaddingPropertyF SheetSideObject::GetSheetSafeAreaPadding() const
339 {
340 auto pipeline = PipelineContext::GetCurrentContext();
341 CHECK_NULL_RETURN(pipeline, PaddingPropertyF());
342 auto safeArea = pipeline->GetSafeArea();
343 PaddingPropertyF padding;
344 padding.left = 0.0f;
345 padding.right = 0.0f;
346 padding.top = CalcLength(safeArea.top_.Length()).GetDimension().ConvertToPx();
347 padding.bottom = CalcLength(safeArea.bottom_.Length()).GetDimension().ConvertToPx();
348 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
349 padding.left = CalcLength(safeArea.left_.Length()).GetDimension().ConvertToPx();
350 } else {
351 padding.right = CalcLength(safeArea.right_.Length()).GetDimension().ConvertToPx();
352 }
353 return padding;
354 }
355
HandleDragStart()356 void SheetSideObject::HandleDragStart()
357 {
358 auto sheetPattern = GetPattern();
359 CHECK_NULL_VOID(sheetPattern);
360 InitScrollProps();
361 sheetPattern->SetIsDragging(true);
362 if (sheetPattern->GetAnimation() && sheetPattern->GetAnimationProcess()) {
363 AnimationUtils::StopAnimation(sheetPattern->GetAnimation());
364 sheetPattern->SetAnimationBreak(true);
365 }
366 currentOffset_ = 0.0f;
367 }
368
HandleDragUpdate(const GestureEvent & info)369 void SheetSideObject::HandleDragUpdate(const GestureEvent& info)
370 {
371 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
372 HandleDragUpdateForRTL(info);
373 } else {
374 HandleDragUpdateForLTR(info);
375 }
376 }
377
HandleDragUpdateForLTR(const GestureEvent & info)378 void SheetSideObject::HandleDragUpdateForLTR(const GestureEvent& info)
379 {
380 auto sheetPattern = GetPattern();
381 CHECK_NULL_VOID(sheetPattern);
382 auto mainDelta = static_cast<float>(info.GetMainDelta());
383 auto host = sheetPattern->GetHost();
384 CHECK_NULL_VOID(host);
385 auto renderContext = host->GetRenderContext();
386 CHECK_NULL_VOID(renderContext);
387 auto lastOffset = currentOffset_;
388 if (currentOffset_ + mainDelta < 0) {
389 return; // can't drag left
390 }
391 currentOffset_ = currentOffset_ + mainDelta;
392 if (NearEqual(currentOffset_, lastOffset)) {
393 return;
394 }
395 auto offsetX = sheetMaxWidth_ - sheetWidth_ + currentOffset_;
396 renderContext->UpdateTransformTranslate({ offsetX, 0.0f, 0.0f });
397 sheetPattern->onWidthDidChange(sheetWidth_ - currentOffset_);
398 }
399
HandleDragUpdateForRTL(const GestureEvent & info)400 void SheetSideObject::HandleDragUpdateForRTL(const GestureEvent& info)
401 {
402 auto sheetPattern = GetPattern();
403 CHECK_NULL_VOID(sheetPattern);
404 auto mainDelta = static_cast<float>(info.GetMainDelta());
405 auto host = sheetPattern->GetHost();
406 CHECK_NULL_VOID(host);
407 auto renderContext = host->GetRenderContext();
408 CHECK_NULL_VOID(renderContext);
409 auto lastOffset = currentOffset_;
410 if (currentOffset_ + mainDelta > 0) {
411 return; // can't drag right
412 }
413 currentOffset_ = currentOffset_ + mainDelta;
414 if (NearEqual(currentOffset_, lastOffset)) {
415 return;
416 }
417 auto offsetX = currentOffset_ < 0 ? currentOffset_ : 0.0f;
418 renderContext->UpdateTransformTranslate({ offsetX, 0.0f, 0.0f });
419 sheetPattern->onWidthDidChange(sheetWidth_ + currentOffset_);
420 }
421
HandleDragEnd(float dragVelocity)422 void SheetSideObject::HandleDragEnd(float dragVelocity)
423 {
424 auto sheetPattern = GetPattern();
425 CHECK_NULL_VOID(sheetPattern);
426 auto host = sheetPattern->GetHost();
427 CHECK_NULL_VOID(host);
428 sheetPattern->SetIsNeedProcessHeight(true);
429 sheetPattern->SetIsDragging(false);
430
431 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
432 HandleDragEndForRTL(dragVelocity);
433 } else {
434 HandleDragEndForLTR(dragVelocity);
435 }
436 }
437
HandleDragEndForLTR(float dragVelocity)438 void SheetSideObject::HandleDragEndForLTR(float dragVelocity)
439 {
440 auto sheetPattern = GetPattern();
441 CHECK_NULL_VOID(sheetPattern);
442 auto currentOffset = currentOffset_;
443
444 if (LessNotEqual(std::abs(dragVelocity), SHEET_VELOCITY_THRESHOLD)) {
445 if (GreatNotEqual(std::abs(currentOffset), sheetWidth_ - std::abs(currentOffset))) {
446 sheetPattern->SheetInteractiveDismiss(BindSheetDismissReason::SLIDE, std::abs(dragVelocity));
447 } else {
448 ModifyFireSheetTransition(std::abs(dragVelocity));
449 }
450 } else {
451 if (LessNotEqual(dragVelocity, 0.0f)) {
452 // return to the original state in the opposite direction.
453 ModifyFireSheetTransition(std::abs(dragVelocity));
454 } else {
455 // when drag velocity is over the threshold.
456 sheetPattern->SheetInteractiveDismiss(BindSheetDismissReason::SLIDE, std::abs(dragVelocity));
457 }
458 }
459 }
460
HandleDragEndForRTL(float dragVelocity)461 void SheetSideObject::HandleDragEndForRTL(float dragVelocity)
462 {
463 auto sheetPattern = GetPattern();
464 CHECK_NULL_VOID(sheetPattern);
465 auto currentOffset = currentOffset_;
466
467 if (LessNotEqual(std::abs(dragVelocity), SHEET_VELOCITY_THRESHOLD)) {
468 if (GreatNotEqual(std::abs(currentOffset), sheetWidth_ - std::abs(currentOffset))) {
469 sheetPattern->SheetInteractiveDismiss(BindSheetDismissReason::SLIDE, std::abs(dragVelocity));
470 } else {
471 ModifyFireSheetTransition(std::abs(dragVelocity));
472 }
473 } else {
474 if (LessNotEqual(dragVelocity, 0.0f)) {
475 // when drag velocity is over the threshold.
476 sheetPattern->SheetInteractiveDismiss(BindSheetDismissReason::SLIDE, std::abs(dragVelocity));
477 } else {
478 // return to the original state in the opposite direction.
479 ModifyFireSheetTransition(std::abs(dragVelocity));
480 }
481 }
482 }
483
ModifyFireSheetTransition(float dragVelocity)484 void SheetSideObject::ModifyFireSheetTransition(float dragVelocity)
485 {
486 TAG_LOGD(AceLogTag::ACE_SHEET, "SideSheet ModifyFireSheetTransition");
487 auto sheetPattern = GetPattern();
488 CHECK_NULL_VOID(sheetPattern);
489 auto host = sheetPattern->GetHost();
490 CHECK_NULL_VOID(host);
491 auto renderContext = host->GetRenderContext();
492 CHECK_NULL_VOID(renderContext);
493 AnimationOption option;
494 const RefPtr<InterpolatingSpring> curve = AceType::MakeRefPtr<InterpolatingSpring>(
495 dragVelocity / SHEET_VELOCITY_THRESHOLD, CURVE_MASS, CURVE_STIFFNESS, CURVE_DAMPING);
496 option.SetCurve(curve);
497 option.SetFillMode(FillMode::FORWARDS);
498
499 auto offsetX = 0.0f;
500 auto width = sheetWidth_;
501 if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
502 offsetX = 0;
503 } else {
504 offsetX = sheetMaxWidth_ - width;
505 }
506
507 CreatePropertyCallback();
508 auto property = sheetPattern->GetProperty();
509 CHECK_NULL_VOID(property);
510 renderContext->AttachNodeAnimatableProperty(property);
511 property->SetPropertyUnit(PropertyUnit::PIXEL_POSITION);
512
513 auto finishCallback = [weak = AceType::WeakClaim(RawPtr(sheetPattern))]() {
514 auto ref = weak.Upgrade();
515 CHECK_NULL_VOID(ref);
516 if (!ref->GetAnimationBreak()) {
517 ref->SetAnimationProcess(false);
518 ref->GetSheetObject()->SetCurrentOffset(0.0f);
519 } else {
520 ref->SetAnimationBreak(false);
521 }
522
523 ref->AvoidAiBar();
524 ref->SetSpringBack(false);
525 };
526
527 auto layoutProperty = host->GetLayoutProperty<SheetPresentationProperty>();
528 CHECK_NULL_VOID(layoutProperty);
529 auto sheetStyle = layoutProperty->GetSheetStyleValue(SheetStyle());
530 auto interactive = sheetStyle.interactive.value_or(false);
531 sheetPattern->SetAnimationProcess(true);
532 property->Set(width - std::abs(currentOffset_));
533 auto pipeline = host->GetContextRefPtr();
534 std::shared_ptr<AnimationUtils::Animation> animation = AnimationUtils::StartAnimation(
535 option,
536 [weak = AceType::WeakClaim(RawPtr(sheetPattern)), renderContext, offsetX, width, interactive]() {
537 auto ref = weak.Upgrade();
538 CHECK_NULL_VOID(ref);
539 if (interactive) {
540 ref->GetProperty()->Set(width);
541 }
542 if (renderContext) {
543 renderContext->UpdateTransformTranslate({ offsetX, 0.0, 0.0f });
544 }
545 },
546 finishCallback, nullptr, pipeline);
547 sheetPattern->SetAnimation(animation);
548 }
549
CreatePropertyCallback()550 void SheetSideObject::CreatePropertyCallback()
551 {
552 auto sheetPattern = GetPattern();
553 CHECK_NULL_VOID(sheetPattern);
554 if (sheetPattern->GetProperty()) {
555 return;
556 }
557 auto propertyCallback = [weak = AceType::WeakClaim(RawPtr(sheetPattern))](float position) {
558 auto ref = weak.Upgrade();
559 CHECK_NULL_VOID(ref);
560 ref->onWidthDidChange(static_cast<int>(position));
561 };
562 auto property = AceType::MakeRefPtr<NodeAnimatablePropertyFloat>(0.0, std::move(propertyCallback));
563 sheetPattern->SetProperty(property);
564 }
565
GetAvoidKeyboardModeByDefault() const566 SheetKeyboardAvoidMode SheetSideObject::GetAvoidKeyboardModeByDefault() const
567 {
568 return SheetKeyboardAvoidMode::TRANSLATE_AND_SCROLL;
569 }
570
BeforeCreateLayoutWrapper()571 void SheetSideObject::BeforeCreateLayoutWrapper()
572 {
573 AvoidKeyboard(false);
574
575 auto sheetPattern = GetPattern();
576 CHECK_NULL_VOID(sheetPattern);
577 auto scrollNode = sheetPattern->GetSheetScrollNode();
578 CHECK_NULL_VOID(scrollNode);
579 auto scrollablePattern = scrollNode->GetPattern<ScrollablePattern>();
580 CHECK_NULL_VOID(scrollablePattern);
581 scrollablePattern->SetNeedFullSafeArea(false);
582 }
583
AvoidKeyboard(bool forceAvoid)584 void SheetSideObject::AvoidKeyboard(bool forceAvoid)
585 {
586 auto sheetPattern = GetPattern();
587 CHECK_NULL_VOID(sheetPattern);
588 auto host = sheetPattern->GetHost();
589 CHECK_NULL_VOID(host);
590 CHECK_NULL_VOID(host->GetFocusHub());
591 auto keyboardAvoidMode = sheetPattern->GetKeyboardAvoidMode();
592 bool isCurrentFocus = host->GetFocusHub()->IsCurrentFocus();
593 if (keyboardAvoidMode == SheetKeyboardAvoidMode::NONE || !isCurrentFocus) {
594 TAG_LOGD(AceLogTag::ACE_SHEET,
595 "Sheet will not avoid keyboard.keyboardAvoidMode:%{public}d, isCurrentFocus:%{public}d.",
596 keyboardAvoidMode, isCurrentFocus);
597 return;
598 }
599 auto pipelineContext = host->GetContext();
600 CHECK_NULL_VOID(pipelineContext);
601 auto manager = pipelineContext->GetSafeAreaManager();
602 auto keyboardHeight = manager->GetKeyboardInset().Length();
603 if (sheetPattern->GetKeyboardHeight() == keyboardHeight && !forceAvoid) {
604 return;
605 }
606 sheetPattern->SetKeyboardHeight(keyboardHeight);
607 if (sheetPattern->GetDismissProcess()) {
608 TAG_LOGD(AceLogTag::ACE_SHEET,
609 "The sheet will disappear, so there's no need to handle canceling keyboard avoidance here.");
610 return;
611 }
612 // 1.handle non upward logic: avoidKeyboardMode::RESIZE_ONLY or avoidKeyboardMode::TRANSLATE_AND_RESIZE
613 resizeDecreasedHeight_ = keyboardHeight;
614 auto heightUp = isCurrentFocus ? GetUpOffsetCaretNeed() : 0.0f;
615 // 2.Side Sheet is not to handle upward logic
616
617 // 3.deal with left height(heightUp), scroll or resize
618 // textInput will be lefted, which depends on the ability of the Scroll Components.
619 // this is different from other sheetType.
620 switch (keyboardAvoidMode) {
621 case SheetKeyboardAvoidMode::RESIZE_ONLY:
622 break;
623 case SheetKeyboardAvoidMode::TRANSLATE_AND_RESIZE:
624 if (NonPositive(heightUp)) {
625 resizeDecreasedHeight_ = 0.0f;
626 }
627 break;
628 case SheetKeyboardAvoidMode::TRANSLATE_AND_SCROLL:
629 default:
630 if (NonPositive(heightUp)) {
631 resizeDecreasedHeight_ = 0.0f;
632 } else {
633 sheetPattern->SetColumnMinSize(NonPositive(resizeDecreasedHeight_));
634 }
635 break;
636 }
637 }
638
GetUpOffsetCaretNeed()639 float SheetSideObject::GetUpOffsetCaretNeed()
640 {
641 // TextFieldManagerNG::GetClickPosition: The upper left corner offset of the cursor position relative to rootNode
642 // TextFieldManagerNG::GetHeight: the cursor Height + 24vp
643 auto sheetPattern = GetPattern();
644 CHECK_NULL_RETURN(sheetPattern, 0.0f);
645 auto host = sheetPattern->GetHost();
646 CHECK_NULL_RETURN(host, 0.0f);
647 auto pipelineContext = host->GetContext();
648 CHECK_NULL_RETURN(pipelineContext, 0.0f);
649 auto manager = pipelineContext->GetSafeAreaManager();
650 auto keyboardHeight = manager->GetKeyboardInset().Length();
651 if (keyboardHeight == 0) {
652 return 0.0f;
653 }
654 auto textFieldManager = DynamicCast<TextFieldManagerNG>(pipelineContext->GetTextFieldManager());
655 // inputH : Distance from input component's Caret to bottom of screen
656 // = caret's offset + caret's height + 24vp
657 if (textFieldManager && !textFieldManager->GetOptionalClickPosition().has_value() &&
658 !pipelineContext->UsingCaretAvoidMode()) {
659 TAG_LOGD(AceLogTag::ACE_SHEET, "illegal caret position, don't calc height this time");
660 return 0.0f;
661 }
662 float inputH = textFieldManager ? (pipelineContext->GetRootHeight() -
663 textFieldManager->GetFocusedNodeCaretRect().Top() - textFieldManager->GetHeight()) : 0.f;
664 // keyboardH : keyboard height + height of the bottom navigation bar
665 auto keyboardH = keyboardHeight + manager->GetSystemSafeArea().bottom_.Length();
666 // The minimum height of the input component from the bottom of the screen after popping up the soft keyboard
667 auto inputMinH = keyboardH;
668 if (inputH >= inputMinH) {
669 // Caret needs not up
670 TAG_LOGD(AceLogTag::ACE_SHEET, "Caret witch in Sheet needs not up");
671 return 0.0f;
672 }
673 // The expected height of the Caret to be lifted
674 return inputMinH - inputH;
675 }
676
FireHeightDidChange()677 void SheetSideObject::FireHeightDidChange()
678 {
679 auto pattern = GetPattern();
680 CHECK_NULL_VOID(pattern);
681 auto preDidHeight = pattern->GetPreDidHeight();
682 if (NearEqual(preDidHeight, sheetHeight_)) {
683 return;
684 }
685 pattern->OnHeightDidChange(sheetHeight_);
686 pattern->SetPreDidHeight(sheetHeight_);
687 }
688 } // namespace OHOS::Ace::NG
689