1 /*
2  * Copyright (c) 2022-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/calendar/calendar_pattern.h"
17 
18 #include <optional>
19 
20 #include "base/geometry/offset.h"
21 #include "base/i18n/localization.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utils.h"
24 #include "core/components_ng/base/frame_node.h"
25 #include "core/components_ng/base/inspector_filter.h"
26 #include "core/components_ng/pattern/badge/badge_layout_property.h"
27 #include "core/components_ng/pattern/calendar/calendar_month_pattern.h"
28 #include "core/components_ng/pattern/calendar_picker/calendar_dialog_view.h"
29 #include "core/components_ng/pattern/swiper/swiper_event_hub.h"
30 #include "core/components_ng/pattern/swiper/swiper_layout_property.h"
31 #include "core/components_ng/pattern/swiper/swiper_pattern.h"
32 #include "core/components_ng/pattern/text/text_pattern.h"
33 
34 namespace OHOS::Ace::NG {
OnAttachToFrameNode()35 void CalendarPattern::OnAttachToFrameNode()
36 {
37     auto host = GetHost();
38     CHECK_NULL_VOID(host);
39     host->GetRenderContext()->SetClipToFrame(true);
40 }
41 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)42 bool CalendarPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
43 {
44     return false;
45 }
46 
SetCalendarControllerNg(const RefPtr<CalendarControllerNg> & calendarController)47 void CalendarPattern::SetCalendarControllerNg(const RefPtr<CalendarControllerNg>& calendarController)
48 {
49     calendarControllerNg_ = calendarController;
50     if (calendarControllerNg_) {
51         calendarControllerNg_->SetCalendarPattern(AceType::WeakClaim(this));
52     }
53 }
54 
OnModifyDone()55 void CalendarPattern::OnModifyDone()
56 {
57     Pattern::OnModifyDone();
58     auto host = GetHost();
59     CHECK_NULL_VOID(host);
60     auto hostNode = DynamicCast<FrameNode>(host);
61     CHECK_NULL_VOID(hostNode);
62     auto hostLayoutProperty = hostNode->GetLayoutProperty();
63     CHECK_NULL_VOID(hostLayoutProperty);
64     auto textDirection = hostLayoutProperty->GetNonAutoLayoutDirection();
65     auto swiperNode = host->GetChildren().front();
66     CHECK_NULL_VOID(swiperNode);
67     auto swiperFrameNode = DynamicCast<FrameNode>(swiperNode);
68     CHECK_NULL_VOID(swiperFrameNode);
69     auto swiperLayoutProperty = swiperFrameNode->GetLayoutProperty();
70     CHECK_NULL_VOID(swiperLayoutProperty);
71     swiperLayoutProperty->UpdateLayoutDirection(textDirection);
72     auto calendarEventHub = host->GetEventHub<CalendarEventHub>();
73     CHECK_NULL_VOID(calendarEventHub);
74     if (swiperFrameNode->GetChildren().size() < 3) {
75         return;
76     }
77     auto preFrameNode = AceType::DynamicCast<FrameNode>(swiperFrameNode->GetChildren().front());
78     CHECK_NULL_VOID(preFrameNode);
79     auto prePattern = preFrameNode->GetPattern<CalendarMonthPattern>();
80     CHECK_NULL_VOID(prePattern);
81     auto iterator = swiperFrameNode->GetChildren().begin();
82     auto currentFrameNode = AceType::DynamicCast<FrameNode>(*(++iterator));
83     CHECK_NULL_VOID(currentFrameNode);
84     auto currentPattern = currentFrameNode->GetPattern<CalendarMonthPattern>();
85     CHECK_NULL_VOID(currentPattern);
86     auto nextFrameNode = AceType::DynamicCast<FrameNode>(swiperFrameNode->GetChildren().back());
87     CHECK_NULL_VOID(nextFrameNode);
88     auto nextPattern = nextFrameNode->GetPattern<CalendarMonthPattern>();
89     CHECK_NULL_VOID(nextPattern);
90 
91     // Set the calendarDay.
92     prePattern->SetCalendarDay(calendarDay_);
93     currentPattern->SetCalendarDay(calendarDay_);
94     nextPattern->SetCalendarDay(calendarDay_);
95 
96     // Flush the focus.
97     FlushFocus(preMonth_);
98     FlushFocus(currentMonth_);
99     FlushFocus(nextMonth_);
100     if (currentPattern->IsCalendarDialog()) {
101         FlushDialogData();
102         UpdateTitleNode();
103     }
104 
105     // Initialize the calendar.
106     if (initialize_) {
107         prePattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
108         currentPattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
109         nextPattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
110         if (currentMonth_.days.empty() && calendarEventHub->GetOnRequestDataEvent()) {
111             FireFirstRequestData();
112         } else {
113             initialize_ = false;
114         }
115         InitSwiperChangeDoneEvent();
116         return;
117     }
118 
119     InitSwiperChangeDoneEvent();
120     // Check JumpTo and BackToToday function.
121     if (backToToday_ || goTo_) {
122         JumpTo(preFrameNode, currentFrameNode, nextFrameNode, swiperFrameNode);
123         return;
124     }
125     auto swiperPattern = swiperFrameNode->GetPattern<SwiperPattern>();
126     CHECK_NULL_VOID(swiperPattern);
127     auto currentIndex = swiperPattern->GetCurrentIndex();
128     currentMonthIndex_ = currentIndex;
129 
130     // Set calendat data according to the index.
131     switch (currentIndex) {
132         case 0: {
133             currentPattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
134             currentFrameNode->MarkModifyDone();
135             currentFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
136             prePattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
137             preFrameNode->MarkModifyDone();
138             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
139             nextPattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
140             nextFrameNode->MarkModifyDone();
141             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
142             return;
143         }
144         case 1: {
145             currentPattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
146             currentFrameNode->MarkModifyDone();
147             currentFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
148             prePattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
149             preFrameNode->MarkModifyDone();
150             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
151             nextPattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
152             nextFrameNode->MarkModifyDone();
153             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
154             return;
155         }
156         case 2: {
157             currentPattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
158             currentFrameNode->MarkModifyDone();
159             currentFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
160             prePattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
161             preFrameNode->MarkModifyDone();
162             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
163             nextPattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
164             nextFrameNode->MarkModifyDone();
165             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
166             return;
167         }
168         default:
169             return;
170     }
171 }
172 
InitSwiperChangeDoneEvent()173 void CalendarPattern::InitSwiperChangeDoneEvent()
174 {
175     auto host = GetHost();
176     CHECK_NULL_VOID(host);
177     auto hostNode = DynamicCast<FrameNode>(host);
178     CHECK_NULL_VOID(hostNode);
179     auto hostLayoutProperty = hostNode->GetLayoutProperty();
180     CHECK_NULL_VOID(hostLayoutProperty);
181     auto textDirection = hostLayoutProperty->GetNonAutoLayoutDirection();
182 
183     auto swiperNode = host->GetChildren().front();
184     CHECK_NULL_VOID(swiperNode);
185     auto swiperFrameNode = DynamicCast<FrameNode>(swiperNode);
186     CHECK_NULL_VOID(swiperFrameNode);
187     auto swiperEventHub = swiperFrameNode->GetEventHub<SwiperEventHub>();
188     CHECK_NULL_VOID(swiperEventHub);
189     auto requestDataCallBack = [weak = WeakClaim(this), textDirection,
190                                     swiperEventHubWeak = WeakPtr<SwiperEventHub>(swiperEventHub)]() {
191         auto pattern = weak.Upgrade();
192         CHECK_NULL_VOID(pattern);
193         auto swiperEventHub = swiperEventHubWeak.Upgrade();
194         CHECK_NULL_VOID(swiperEventHub);
195         auto direction = swiperEventHub->GetDirection();
196         if (textDirection == TextDirection::RTL && !pattern->isClickEvent_) {
197             if (direction == NG::Direction::NEXT) {
198                 direction = NG::Direction::PRE;
199             } else {
200                 direction = NG::Direction::NEXT;
201             }
202         }
203         pattern->isClickEvent_ = false;
204         if (direction == NG::Direction::NEXT) {
205             pattern->FireRequestData(MonthState::NEXT_MONTH);
206             pattern->SetMoveDirection(NG::Direction::NEXT);
207         } else {
208             pattern->FireRequestData(MonthState::PRE_MONTH);
209             pattern->SetMoveDirection(NG::Direction::PRE);
210         }
211         pattern->ReadTitleNode();
212         pattern->ClearChildrenFocus();
213     };
214     swiperEventHub->SetChangeDoneEvent(requestDataCallBack);
215     for (const auto& calendarMonthNode : swiperNode->GetChildren()) {
216         auto calenderMonthFrameNode = AceType::DynamicCast<FrameNode>(calendarMonthNode);
217         CHECK_NULL_VOID(calenderMonthFrameNode);
218         auto monthLayoutProperty = calenderMonthFrameNode->GetLayoutProperty();
219         CHECK_NULL_VOID(monthLayoutProperty);
220         monthLayoutProperty->UpdateLayoutDirection(textDirection);
221         calenderMonthFrameNode->MarkModifyDone();
222         calenderMonthFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
223     }
224 }
225 
FireFirstRequestData()226 void CalendarPattern::FireFirstRequestData()
227 {
228     auto host = GetHost();
229     CHECK_NULL_VOID(host);
230     auto eventHub = GetEventHub<CalendarEventHub>();
231     CHECK_NULL_VOID(eventHub);
232     auto json = JsonUtil::Create(true);
233     auto currentMonth = calendarDay_.month;
234     json->Put("currentYear", currentMonth.year);
235     json->Put("currentMonth", currentMonth.month);
236     json->Put("year", currentMonth.year);
237     json->Put("month", currentMonth.month);
238     json->Put("MonthState", 0);
239     eventHub->UpdateRequestDataEvent(json->ToString());
240 }
241 
FireRequestData(MonthState monthState)242 void CalendarPattern::FireRequestData(MonthState monthState)
243 {
244     auto host = GetHost();
245     CHECK_NULL_VOID(host);
246     auto eventHub = GetEventHub<CalendarEventHub>();
247     CHECK_NULL_VOID(eventHub);
248     auto json = JsonUtil::Create(true);
249     if (monthState == MonthState::PRE_MONTH) {
250         json->Put("MonthState", 1);
251         json->Put("year", preMonth_.year);
252         json->Put("month", preMonth_.month);
253     } else if (monthState == MonthState::NEXT_MONTH) {
254         json->Put("MonthState", 2);
255         json->Put("year", nextMonth_.year);
256         json->Put("month", nextMonth_.month);
257     }
258     json->Put("currentYear", calendarDay_.month.year);
259     json->Put("currentMonth", calendarDay_.month.month);
260     eventHub->UpdateRequestDataEvent(json->ToString());
261 }
262 
FireGoToRequestData(int32_t year,int32_t month,int32_t day)263 void CalendarPattern::FireGoToRequestData(int32_t year, int32_t month, int32_t day)
264 {
265     auto host = GetHost();
266     CHECK_NULL_VOID(host);
267     auto eventHub = GetEventHub<CalendarEventHub>();
268     CHECK_NULL_VOID(eventHub);
269     auto json = JsonUtil::Create(true);
270     auto currentMonth = calendarDay_.month;
271     json->Put("currentYear", currentMonth.year);
272     json->Put("currentMonth", currentMonth.month);
273     json->Put("year", year);
274     json->Put("month", month);
275     json->Put("MonthState", 0);
276     goToCalendarDay_ = day;
277     goToCalendarMonth_ = month;
278     goToCalendarYear_ = year;
279     eventHub->UpdateRequestDataEvent(json->ToString());
280 }
281 
JumpTo(ObtainedMonth & obtainedMonth)282 void CalendarPattern::JumpTo(ObtainedMonth& obtainedMonth)
283 {
284     for (auto& day : obtainedMonth.days) {
285         if (day.month.year == goToCalendarYear_ && day.month.month == goToCalendarMonth_ &&
286             day.day == goToCalendarDay_) {
287             day.focused = true;
288         } else {
289             day.focused = false;
290         }
291     }
292 }
293 
JumpTo(const RefPtr<FrameNode> & preFrameNode,const RefPtr<FrameNode> & curFrameNode,const RefPtr<FrameNode> & nextFrameNode,const RefPtr<FrameNode> & swiperFrameNode)294 void CalendarPattern::JumpTo(const RefPtr<FrameNode>& preFrameNode, const RefPtr<FrameNode>& curFrameNode,
295     const RefPtr<FrameNode>& nextFrameNode, const RefPtr<FrameNode>& swiperFrameNode)
296 {
297     auto prePattern = preFrameNode->GetPattern<CalendarMonthPattern>();
298     CHECK_NULL_VOID(prePattern);
299     auto currentPattern = curFrameNode->GetPattern<CalendarMonthPattern>();
300     CHECK_NULL_VOID(currentPattern);
301     auto nextPattern = nextFrameNode->GetPattern<CalendarMonthPattern>();
302     CHECK_NULL_VOID(nextPattern);
303     auto swiperPattern = swiperFrameNode->GetPattern<SwiperPattern>();
304     CHECK_NULL_VOID(swiperPattern);
305     auto currentIndex = swiperPattern->GetCurrentIndex();
306     currentMonthIndex_ = currentIndex;
307     if (goTo_) {
308         JumpTo(currentMonth_);
309     }
310     switch (currentIndex) {
311         case 0: {
312             prePattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
313             if (backToToday_) {
314                 prePattern->SetCalendarDay(calendarDay_);
315             }
316             currentPattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
317             nextPattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
318             curFrameNode->MarkModifyDone();
319             curFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
320             preFrameNode->MarkModifyDone();
321             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
322             nextFrameNode->MarkModifyDone();
323             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
324             break;
325         }
326         case 1: {
327             prePattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
328             currentPattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
329             if (backToToday_) {
330                 currentPattern->SetCalendarDay(calendarDay_);
331             }
332             nextPattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
333             curFrameNode->MarkModifyDone();
334             curFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
335             preFrameNode->MarkModifyDone();
336             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
337             nextFrameNode->MarkModifyDone();
338             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
339             break;
340         }
341         case 2: {
342             prePattern->SetMonthData(nextMonth_, MonthState::NEXT_MONTH);
343             currentPattern->SetMonthData(preMonth_, MonthState::PRE_MONTH);
344             nextPattern->SetMonthData(currentMonth_, MonthState::CUR_MONTH);
345             if (backToToday_) {
346                 nextPattern->SetCalendarDay(calendarDay_);
347             }
348             curFrameNode->MarkModifyDone();
349             curFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
350             preFrameNode->MarkModifyDone();
351             preFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
352             nextFrameNode->MarkModifyDone();
353             nextFrameNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
354             break;
355         }
356         default:
357             break;
358     }
359     backToToday_ = false;
360     goTo_ = false;
361 }
362 
FlushFocus(ObtainedMonth & obtainedMonth)363 void CalendarPattern::FlushFocus(ObtainedMonth& obtainedMonth)
364 {
365     if (obtainedMonth.days.empty()) {
366         LOGE("month data is empty");
367         return;
368     }
369     bool flag = false;
370     for (auto& day : obtainedMonth.days) {
371         day.focused = day.month.year == calendarDay_.month.year && day.month.month == calendarDay_.month.month &&
372                       day.day == calendarDay_.day;
373         if (!flag && day.focused == true) {
374             flag = true;
375         }
376     }
377     if (!flag) {
378         obtainedMonth.days[0].focused = true;
379     }
380 }
381 
FlushDialogData()382 void CalendarPattern::FlushDialogData()
383 {
384     FlushDialogMonthData(preMonth_);
385     FlushDialogMonthData(currentMonth_);
386     FlushDialogMonthData(nextMonth_);
387 }
388 
FlushDialogMonthData(ObtainedMonth & obtainedMonth)389 void CalendarPattern::FlushDialogMonthData(ObtainedMonth& obtainedMonth)
390 {
391     if (obtainedMonth.days.empty()) {
392         return;
393     }
394     for (auto& day : obtainedMonth.days) {
395         day.isSelected = day.month.year == static_cast<int32_t>(selectedDay_.GetYear()) &&
396                          day.month.month == static_cast<int32_t>(selectedDay_.GetMonth()) &&
397                          day.day == static_cast<int32_t>(selectedDay_.GetDay());
398     }
399 }
400 
ClearChildrenFocus()401 void CalendarPattern::ClearChildrenFocus()
402 {
403     auto host = GetHost();
404     CHECK_NULL_VOID(host);
405     auto swiperNode = host->GetChildren().front();
406     CHECK_NULL_VOID(swiperNode);
407     auto swiperFrameNode = DynamicCast<FrameNode>(swiperNode);
408     CHECK_NULL_VOID(swiperFrameNode);
409     auto preFrameNode = AceType::DynamicCast<FrameNode>(swiperFrameNode->GetChildren().front());
410     CHECK_NULL_VOID(preFrameNode);
411     auto prePattern = preFrameNode->GetPattern<CalendarMonthPattern>();
412     CHECK_NULL_VOID(prePattern);
413     auto iterator = swiperFrameNode->GetChildren().begin();
414     auto currentFrameNode = AceType::DynamicCast<FrameNode>(*(++iterator));
415     CHECK_NULL_VOID(currentFrameNode);
416     auto currentPattern = currentFrameNode->GetPattern<CalendarMonthPattern>();
417     CHECK_NULL_VOID(currentPattern);
418     auto nextFrameNode = AceType::DynamicCast<FrameNode>(swiperFrameNode->GetChildren().back());
419     CHECK_NULL_VOID(nextFrameNode);
420     auto nextPattern = nextFrameNode->GetPattern<CalendarMonthPattern>();
421     CHECK_NULL_VOID(nextPattern);
422     prePattern->ClearFocusCalendarDay();
423     currentPattern->ClearFocusCalendarDay();
424     nextPattern->ClearFocusCalendarDay();
425 }
426 
ReadTitleNode()427 void CalendarPattern::ReadTitleNode()
428 {
429     auto host = GetHost();
430     CHECK_NULL_VOID(host);
431     host->OnAccessibilityEvent(AccessibilityEventType::ANNOUNCE_FOR_ACCESSIBILITY, selectedMonth_);
432 }
433 
UpdateTitleNode()434 void CalendarPattern::UpdateTitleNode()
435 {
436     if (!HasTitleNode()) {
437         return;
438     }
439     auto textTitleNode = FrameNode::GetOrCreateFrameNode(
440         V2::TEXT_ETS_TAG, GetTitleId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
441     CHECK_NULL_VOID(textTitleNode);
442     auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
443     CHECK_NULL_VOID(textLayoutProperty);
444 
445     DateTime date;
446     date.year = currentMonth_.year < 0 ? 0 : static_cast<uint32_t>(currentMonth_.year);
447     date.month = currentMonth_.month - 1 < 0
448                      ? 0
449                      : static_cast<uint32_t>(currentMonth_.month - 1); // W3C's month start from 0 to 11
450     auto titleDate = Localization::GetInstance()->FormatDateTime(date, "YYYYMM");
451     textLayoutProperty->UpdateContent(titleDate);
452     selectedMonth_ = titleDate;
453     auto pipelineContext = GetHost()->GetContext();
454     CHECK_NULL_VOID(pipelineContext);
455     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
456     CHECK_NULL_VOID(theme);
457     auto fontSizeScale = pipelineContext->GetFontScale();
458     auto fontSize = theme->GetCalendarTitleFontSize();
459     if (fontSizeScale < theme->GetCalendarPickerLargeScale() || CalendarDialogView::CheckOrientationChange()) {
460         textLayoutProperty->UpdateFontSize(fontSize);
461     } else {
462         textLayoutProperty->UpdateMaxLines(2);
463         fontSizeScale = fontSizeScale > theme->GetCalendarPickerLargerScale() ? theme->GetCalendarPickerLargerScale()
464                                                                               : fontSizeScale;
465         textLayoutProperty->UpdateFontSize(fontSize * fontSizeScale);
466     }
467 
468     textTitleNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
469     textTitleNode->MarkModifyDone();
470 }
471 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const472 void CalendarPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
473 {
474     /* no fixed attr below, just return */
475     if (filter.IsFastFilter()) {
476         return;
477     }
478     auto host = GetHost();
479     CHECK_NULL_VOID(host);
480     auto swiperNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
481     CHECK_NULL_VOID(swiperNode);
482     auto swiperLayoutProperty = swiperNode->GetLayoutProperty<SwiperLayoutProperty>();
483     CHECK_NULL_VOID(swiperLayoutProperty);
484     json->PutExtAttr("needSlide",
485         !swiperLayoutProperty->GetDisableSwipe().value_or(false) ? "true" : "false", filter);
486     json->PutExtAttr("direction",
487         swiperLayoutProperty->GetDirection().value_or(Axis::HORIZONTAL) == Axis::VERTICAL ? "0" : "1", filter);
488 }
489 
490 } // namespace OHOS::Ace::NG
491