• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/time_picker/timepicker_row_pattern.h"
17 #include <cstdint>
18 
19 #include "base/geometry/ng/size_t.h"
20 #include "base/utils/utils.h"
21 #include "core/components/picker/picker_theme.h"
22 #include "core/components_ng/pattern/button/button_pattern.h"
23 #include "core/components_ng/pattern/stack/stack_pattern.h"
24 #include "core/components_ng/pattern/text/text_pattern.h"
25 #include "core/components_ng/pattern/time_picker/toss_animation_controller.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/pipeline_ng/ui_task_scheduler.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr int32_t CHILD_WITH_AMPM_SIZE = 3;
32 constexpr int32_t CHILD_WITHOUT_AMPM_SIZE = 2;
33 constexpr uint32_t AM_PM_HOUR_12 = 12;
34 constexpr uint32_t AM_PM_HOUR_11 = 11;
35 const int32_t AM_PM_COUNT = 3;
36 const Dimension PRESS_INTERVAL = 4.0_vp;
37 const Dimension PRESS_RADIUS = 8.0_vp;
38 const int32_t UNOPTION_COUNT = 2;
39 const int32_t AMPMDEFAULTPOSITION = 0;
40 const int32_t AMPM_FORWARD_WITHSECOND = 3;
41 const int32_t AMPM_FORWARD_WITHOUTSECOND = 2;
42 const int32_t AMPM_BACKWARD_WITHSECOND = -3;
43 const int32_t AMPM_BACKWARD_WITHOUTSECOND = -2;
44 const int32_t CHILD_INDEX_FIRST = 0;
45 const int32_t CHILD_INDEX_SECOND = 1;
46 const int32_t CHILD_INDEX_THIRD = 2;
47 const int32_t CHILD_INDEX_FOURTH = 3;
48 constexpr float DISABLE_ALPHA = 0.6f;
49 const Dimension FOCUS_OFFSET = 2.0_vp;
50 const int32_t RATE = 2;
51 } // namespace
52 
OnAttachToFrameNode()53 void TimePickerRowPattern::OnAttachToFrameNode()
54 {
55     auto host = GetHost();
56     CHECK_NULL_VOID(host);
57     host->GetRenderContext()->SetClipToFrame(true);
58     host->GetRenderContext()->UpdateClipEdge(true);
59 }
60 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)61 bool TimePickerRowPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
62 {
63     CHECK_NULL_RETURN(dirty, false);
64     SetButtonIdeaSize();
65     return true;
66 }
67 
SetButtonIdeaSize()68 void TimePickerRowPattern::SetButtonIdeaSize()
69 {
70     auto host = GetHost();
71     CHECK_NULL_VOID(host);
72     auto context = host->GetContext();
73     CHECK_NULL_VOID(context);
74     auto pickerTheme = context->GetTheme<PickerTheme>();
75     CHECK_NULL_VOID(pickerTheme);
76     auto children = host->GetChildren();
77     auto height = pickerTheme->GetDividerSpacing();
78     for (const auto& child : children) {
79         auto childNode = DynamicCast<FrameNode>(child);
80         CHECK_NULL_VOID(childNode);
81         auto width = childNode->GetGeometryNode()->GetFrameSize().Width();
82         auto defaultWidth = height.ConvertToPx() * 2;
83         if (width > defaultWidth) {
84             width = static_cast<float>(defaultWidth);
85         }
86         auto timePickerColumnNode = DynamicCast<FrameNode>(childNode->GetLastChild());
87         CHECK_NULL_VOID(timePickerColumnNode);
88         auto columnNodeHeight = timePickerColumnNode->GetGeometryNode()->GetFrameSize().Height();
89         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
90         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
91         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
92         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
93         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
94         auto standardButtonHeight = static_cast<float>((height - PRESS_INTERVAL).ConvertToPx());
95         auto maxButtonHeight = static_cast<float>(columnNodeHeight);
96         auto buttonHeight = Dimension(std::min(standardButtonHeight, maxButtonHeight), DimensionUnit::PX);
97         buttonLayoutProperty->UpdateUserDefinedIdealSize(
98             CalcSize(CalcLength(width - PRESS_INTERVAL.ConvertToPx()), CalcLength(buttonHeight)));
99         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
100         buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
101         buttonNode->MarkModifyDone();
102         buttonNode->MarkDirtyNode();
103         if (GetIsShowInDialog() && GreatNotEqual(standardButtonHeight, maxButtonHeight) &&
104             GreatNotEqual(maxButtonHeight, 0.0f)) {
105             auto parentNode = DynamicCast<FrameNode>(host->GetParent());
106             CHECK_NULL_VOID(parentNode);
107             parentNode->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
108         }
109     }
110 }
111 
ColumnPatternInitHapticController()112 void TimePickerRowPattern::ColumnPatternInitHapticController()
113 {
114     if (!isHapticChanged_) {
115         return;
116     }
117 
118     isHapticChanged_ = false;
119     for (auto iter = allChildNode_.begin(); iter != allChildNode_.end(); iter++) {
120         auto columnNode = iter->second.Upgrade();
121         if (!columnNode) {
122             continue;
123         }
124         auto pattern = columnNode->GetPattern<TimePickerColumnPattern>();
125         if (!pattern) {
126             continue;
127         }
128         pattern->InitHapticController(columnNode);
129     }
130 }
131 
OnModifyDone()132 void TimePickerRowPattern::OnModifyDone()
133 {
134     if (isFiredTimeChange_ && !isForceUpdate_ && !isDateTimeOptionUpdate_) {
135         isFiredTimeChange_ = false;
136         ColumnPatternInitHapticController();
137         return;
138     }
139 
140     isHapticChanged_ = false;
141     isForceUpdate_ = false;
142     isDateTimeOptionUpdate_ = false;
143     auto host = GetHost();
144     CHECK_NULL_VOID(host);
145     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
146     CHECK_NULL_VOID(pickerProperty);
147     wheelModeEnabled_ = pickerProperty->GetLoopValue(true);
148     UpdateLanguageAndAmPmTimeOrder();
149     CreateOrDeleteSecondNode();
150     CreateAmPmNode();
151     OnColumnsBuilding();
152     FlushColumn();
153     InitDisabled();
154     SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag, bool add, uint32_t index, bool notify) {
155         auto refPtr = weak.Upgrade();
156         CHECK_NULL_VOID(refPtr);
157         refPtr->HandleColumnChange(tag, add, index, notify);
158     });
159     SetEventCallback([weak = WeakClaim(this)](bool refresh) {
160         auto refPtr = weak.Upgrade();
161         CHECK_NULL_VOID(refPtr);
162         refPtr->FireChangeEvent(refresh);
163     });
164     auto focusHub = host->GetFocusHub();
165     if (focusHub) {
166         InitOnKeyEvent(focusHub);
167     }
168     if (HasTitleNode()) {
169         auto textTitleNode = FrameNode::GetOrCreateFrameNode(
170             V2::TEXT_ETS_TAG, GetTitleId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
171         auto str = GetDialogTitleDate();
172         CHECK_NULL_VOID(textTitleNode);
173         auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
174         CHECK_NULL_VOID(textLayoutProperty);
175         textLayoutProperty->UpdateContent(str.ToString(false));
176     }
177     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
178 }
179 
InitDisabled()180 void TimePickerRowPattern::InitDisabled()
181 {
182     auto host = GetHost();
183     CHECK_NULL_VOID(host);
184     auto eventHub = host->GetEventHub<EventHub>();
185     CHECK_NULL_VOID(eventHub);
186     enabled_ = eventHub->IsEnabled();
187     auto renderContext = host->GetRenderContext();
188     CHECK_NULL_VOID(renderContext);
189     if (!enabled_) {
190         renderContext->UpdateOpacity(curOpacity_ * DISABLE_ALPHA);
191     }
192     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
193 }
194 
CreateAmPmNode()195 void TimePickerRowPattern::CreateAmPmNode()
196 {
197     auto host = GetHost();
198     CHECK_NULL_VOID(host);
199     auto context = host->GetContext();
200     CHECK_NULL_VOID(context);
201     auto pickerTheme = context->GetTheme<PickerTheme>();
202     CHECK_NULL_VOID(pickerTheme);
203     auto height = pickerTheme->GetDividerSpacing();
204     if (!GetHour24() && !HasAmPmNode()) {
205         auto amPmColumnNode = FrameNode::GetOrCreateFrameNode(
206             V2::COLUMN_ETS_TAG, GetAmPmId(), []() { return AceType::MakeRefPtr<TimePickerColumnPattern>(); });
207         CHECK_NULL_VOID(amPmColumnNode);
208         for (uint32_t index = 0; index < AM_PM_COUNT; index++) {
209             auto textNode = FrameNode::CreateFrameNode(
210                 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
211             CHECK_NULL_VOID(textNode);
212             textNode->MountToParent(amPmColumnNode);
213         }
214         SetColumn(amPmColumnNode);
215         auto stackAmPmNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
216             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
217         auto buttonNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
218             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
219         auto blendNodeId = ElementRegister::GetInstance()->MakeUniqueId();
220         auto columnBlendNode = FrameNode::GetOrCreateFrameNode(
221             V2::COLUMN_ETS_TAG, blendNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
222         buttonNode->MountToParent(stackAmPmNode);
223         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
224         amPmColumnNode->MountToParent(columnBlendNode);
225         columnBlendNode->MountToParent(stackAmPmNode);
226         auto layoutProperty = stackAmPmNode->GetLayoutProperty<LayoutProperty>();
227         layoutProperty->UpdateAlignment(Alignment::CENTER);
228         layoutProperty->UpdateLayoutWeight(1);
229         amPmTimeOrder_ == "01" ? stackAmPmNode->MountToParent(host) : stackAmPmNode->MountToParent(host, 0);
230         if (SetAmPmButtonIdeaSize() > 0) {
231             auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
232             buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
233             buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
234             buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
235             buttonLayoutProperty->UpdateUserDefinedIdealSize(
236                 CalcSize(CalcLength(SetAmPmButtonIdeaSize()), CalcLength(height - PRESS_INTERVAL)));
237             buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
238             buttonNode->MarkModifyDone();
239             buttonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
240         }
241         host->MarkModifyDone();
242         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
243     }
244 }
245 
CreateOrDeleteSecondNode()246 void TimePickerRowPattern::CreateOrDeleteSecondNode()
247 {
248     auto host = GetHost();
249     CHECK_NULL_VOID(host);
250     if (!HasSecondNode()) {
251         if (hasSecond_) {
252             auto secondColumnNode = FrameNode::GetOrCreateFrameNode(
253                 V2::COLUMN_ETS_TAG, GetSecondId(), []() { return AceType::MakeRefPtr<TimePickerColumnPattern>(); });
254             CHECK_NULL_VOID(secondColumnNode);
255             for (uint32_t index = 0; index < GetShowCount(); index++) {
256                 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG,
257                     ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
258                 CHECK_NULL_VOID(textNode);
259                 textNode->MarkModifyDone();
260                 textNode->MountToParent(secondColumnNode);
261             }
262             SetColumn(secondColumnNode);
263             auto stackSecondNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
264                 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
265             auto buttonSecondNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
266                 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
267             auto blendNodeId = ElementRegister::GetInstance()->MakeUniqueId();
268             auto columnBlendNode = FrameNode::GetOrCreateFrameNode(
269                 V2::COLUMN_ETS_TAG, blendNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
270             buttonSecondNode->MarkModifyDone();
271             buttonSecondNode->MountToParent(stackSecondNode);
272             secondColumnNode->MarkModifyDone();
273             secondColumnNode->MountToParent(columnBlendNode);
274             columnBlendNode->MarkModifyDone();
275             columnBlendNode->MountToParent(stackSecondNode);
276             auto layoutProperty = stackSecondNode->GetLayoutProperty<LayoutProperty>();
277             layoutProperty->UpdateAlignment(Alignment::CENTER);
278             layoutProperty->UpdateLayoutWeight(1);
279             stackSecondNode->MarkModifyDone();
280             MountSecondNode(stackSecondNode);
281             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
282         }
283     } else {
284         if (!hasSecond_) {
285             RemoveSecondNode();
286             secondId_.reset();
287             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
288         }
289     }
290 }
291 
MountSecondNode(const RefPtr<FrameNode> & stackSecondNode)292 void TimePickerRowPattern::MountSecondNode(const RefPtr<FrameNode>& stackSecondNode)
293 {
294     auto host = GetHost();
295     CHECK_NULL_VOID(host);
296     int32_t secondNodePosition = static_cast<int32_t>(host->GetChildren().size()) - 1;
297     if (!HasAmPmNode()) {
298         if (language_ == "ug") {
299             secondNodePosition = CHILD_INDEX_FIRST;
300         }
301     } else {
302         if (amPmTimeOrder_ == "01") {
303             secondNodePosition = CHILD_INDEX_THIRD;
304         } else if (language_ == "ug") {
305             secondNodePosition = CHILD_INDEX_SECOND;
306         }
307     }
308     stackSecondNode->MountToParent(host, secondNodePosition);
309 }
310 
RemoveSecondNode()311 void TimePickerRowPattern::RemoveSecondNode()
312 {
313     auto host = GetHost();
314     CHECK_NULL_VOID(host);
315     int32_t secondNodePosition = static_cast<int32_t>(host->GetChildren().size()) - 1;
316     if (!HasAmPmNode()) {
317         if (language_ == "ug") {
318             secondNodePosition = CHILD_INDEX_FIRST;
319         }
320     } else {
321         if (amPmTimeOrder_ == "01") {
322             secondNodePosition = CHILD_INDEX_THIRD;
323         } else if (language_ == "ug") {
324             secondNodePosition = CHILD_INDEX_SECOND;
325         }
326     }
327     host->RemoveChildAtIndex(secondNodePosition);
328 }
329 
SetAmPmButtonIdeaSize()330 double TimePickerRowPattern::SetAmPmButtonIdeaSize()
331 {
332     auto host = GetHost();
333     CHECK_NULL_RETURN(host, 0);
334     auto children = host->GetChildren();
335     float width = 0.0f;
336     for (const auto& child : children) {
337         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
338         CHECK_NULL_RETURN(buttonNode, 0);
339         width = buttonNode->GetGeometryNode()->GetFrameSize().Width();
340     }
341     if (width > 0) {
342         return width;
343     }
344     return 0;
345 }
SetEventCallback(EventCallback && value)346 void TimePickerRowPattern::SetEventCallback(EventCallback&& value)
347 {
348     auto host = GetHost();
349     CHECK_NULL_VOID(host);
350     auto children = host->GetChildren();
351     for (const auto& child : children) {
352         auto stackNode = DynamicCast<FrameNode>(child);
353         CHECK_NULL_VOID(stackNode);
354         auto columnBlendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
355         CHECK_NULL_VOID(columnBlendNode);
356         auto childNode = DynamicCast<FrameNode>(columnBlendNode->GetLastChild());
357         CHECK_NULL_VOID(childNode);
358         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
359         CHECK_NULL_VOID(timePickerColumnPattern);
360         timePickerColumnPattern->SetEventCallback(std::move(value));
361     }
362 }
363 
FireChangeEvent(bool refresh)364 void TimePickerRowPattern::FireChangeEvent(bool refresh)
365 {
366     if (refresh) {
367         auto timePickerEventHub = GetEventHub<TimePickerEventHub>();
368         CHECK_NULL_VOID(timePickerEventHub);
369         auto str = GetSelectedObject(true);
370         auto info = std::make_shared<DatePickerChangeEvent>(str);
371         timePickerEventHub->FireChangeEvent(info.get());
372         timePickerEventHub->FireDialogChangeEvent(str);
373         firedTimeStr_ = str;
374     }
375 }
376 
GetSelectedObject(bool isColumnChange,int32_t status)377 std::string TimePickerRowPattern::GetSelectedObject(bool isColumnChange, int32_t status)
378 {
379     auto time = selectedTime_;
380     if (isColumnChange) {
381         time = GetCurrentTime();
382     }
383     return time.ToString(true, hasSecond_, status);
384 }
385 
GetCurrentTime()386 PickerTime TimePickerRowPattern::GetCurrentTime()
387 {
388     PickerTime time;
389     UpdateAllChildNode();
390     auto amPmColumn = allChildNode_["amPm"].Upgrade();
391     auto hourColumn = allChildNode_["hour"].Upgrade();
392     auto minuteColumn = allChildNode_["minute"].Upgrade();
393     CHECK_NULL_RETURN(hourColumn, time);
394     CHECK_NULL_RETURN(minuteColumn, time);
395     auto hourPickerColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
396     CHECK_NULL_RETURN(hourPickerColumnPattern, time);
397     auto minutePickerColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
398     CHECK_NULL_RETURN(minutePickerColumnPattern, time);
399 
400     if (GetHour24()) {
401         time.SetHour(hourPickerColumnPattern->GetCurrentIndex()); // hour from 0 to 23, index from 0 to 23
402     } else if (amPmColumn) {
403         auto amPmPickerColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
404         CHECK_NULL_RETURN(amPmPickerColumnPattern, time);
405         time.SetHour(GetHourFromAmPm(
406             amPmPickerColumnPattern->GetCurrentIndex() == 0, hourPickerColumnPattern->GetCurrentIndex() + 1));
407     }
408 
409     time.SetMinute(minutePickerColumnPattern->GetCurrentIndex()); // minute from 0 to 59, index from 0 to 59
410     if (hasSecond_) {
411         auto secondColumn = allChildNode_["second"].Upgrade();
412         CHECK_NULL_RETURN(secondColumn, time);
413         auto secondPickerColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
414         CHECK_NULL_RETURN(secondPickerColumnPattern, time);
415         time.SetSecond(secondPickerColumnPattern->GetCurrentIndex()); // second from 0 to 59, index from 0 to 59
416     }
417     return time;
418 }
419 
GetHourFromAmPm(bool isAm,uint32_t amPmhour) const420 uint32_t TimePickerRowPattern::GetHourFromAmPm(bool isAm, uint32_t amPmhour) const
421 {
422     if (isAm) {
423         if (amPmhour == AM_PM_HOUR_12) { // AM 12:00 means 00:00
424             return 0;
425         }
426         return amPmhour;
427     }
428     if (amPmhour == AM_PM_HOUR_12) { // PM 12 means 12:00
429         return AM_PM_HOUR_12;
430     }
431     return amPmhour + AM_PM_HOUR_12; // need add 12 hour to 24 hours style
432 }
433 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)434 void TimePickerRowPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, bool needNotify)
435 {
436     std::vector<RefPtr<FrameNode>> tags;
437     for (const auto& tag : tags) {
438         auto iter = std::find_if(timePickerColumns_.begin(), timePickerColumns_.end(), [&tag](const auto& c) {
439                 auto column = c.Upgrade();
440                 return column && column->GetId() == tag->GetId();
441             });
442         if (iter != timePickerColumns_.end()) {
443             auto timePickerColumn = (*iter).Upgrade();
444             CHECK_NULL_VOID(timePickerColumn);
445             auto timePickerColumnPattern = timePickerColumn->GetPattern<TimePickerColumnPattern>();
446             CHECK_NULL_VOID(timePickerColumnPattern);
447             timePickerColumnPattern->FlushCurrentOptions();
448         }
449     }
450 }
451 
OnFontConfigurationUpdate()452 void TimePickerRowPattern::OnFontConfigurationUpdate()
453 {
454     CHECK_NULL_VOID(closeDialogEvent_);
455     closeDialogEvent_();
456 }
OnLanguageConfigurationUpdate()457 void TimePickerRowPattern::OnLanguageConfigurationUpdate()
458 {
459     FlushAmPmFormatString();
460     UpdateLanguageAndAmPmTimeOrder();
461     if (!GetHour24()) {
462         auto host = GetHost();
463         CHECK_NULL_VOID(host);
464         auto children = host->GetChildren();
465         auto iter = children.begin();
466         CHECK_NULL_VOID(*iter);
467         auto amPmNode = *iter;
468         CHECK_NULL_VOID(amPmNode);
469         if (amPmTimeOrder_ == "01" && isAmPmTimeOrderUpdate_) {
470             // if hasSecond_ is true, then amPmNode should be moved from slot 0 to 3, otherwise from slot 0 to 2
471             hasSecond_ ? amPmNode->MovePosition(3) : amPmNode->MovePosition(2);
472         } else if (amPmTimeOrder_ == "10" && isAmPmTimeOrderUpdate_) {
473             // if hasSecond_ is true, then amPmNode should be moved from slot 3 to 0, otherwise form slot 2 to 0
474             hasSecond_ ? std::advance(iter, 3) : std::advance(iter, 2);
475             amPmNode = *iter;
476             CHECK_NULL_VOID(amPmNode);
477             amPmNode->MovePosition(0);
478         }
479         UpdateNodePositionForUg();
480         auto layoutProperty = AceType::DynamicCast<FrameNode>(amPmNode)->GetLayoutProperty<LayoutProperty>();
481         layoutProperty->UpdateAlignment(Alignment::CENTER);
482         layoutProperty->UpdateLayoutWeight(1);
483         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
484     }
485     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
486     CHECK_NULL_VOID(buttonConfirmNode);
487     auto confirmNode = AceType::DynamicCast<FrameNode>(buttonConfirmNode->GetFirstChild());
488     CHECK_NULL_VOID(confirmNode);
489     auto confirmNodeLayout = confirmNode->GetLayoutProperty<TextLayoutProperty>();
490     CHECK_NULL_VOID(confirmNodeLayout);
491     confirmNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.ok"));
492     confirmNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
493 
494     auto buttonCancelNode = weakButtonCancel_.Upgrade();
495     CHECK_NULL_VOID(buttonCancelNode);
496     auto cancelNode = AceType::DynamicCast<FrameNode>(buttonCancelNode->GetFirstChild());
497     CHECK_NULL_VOID(cancelNode);
498     auto cancelNodeLayout = cancelNode->GetLayoutProperty<TextLayoutProperty>();
499     CHECK_NULL_VOID(cancelNodeLayout);
500     cancelNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.cancel"));
501     cancelNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
502 }
503 
UpdateNodePositionForUg()504 void TimePickerRowPattern::UpdateNodePositionForUg()
505 {
506     if (!isPreLanguageUg_ && language_ != "ug") {
507         return;
508     }
509 
510     auto host = GetHost();
511     CHECK_NULL_VOID(host);
512     // ug's node order is S:M:H, need to change it to H:M:S
513     if (isPreLanguageUg_ && isAmPmTimeOrderUpdate_) {
514         if (hasSecond_) {
515             auto secondNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
516             CHECK_NULL_VOID(secondNode);
517             secondNode->MovePosition(CHILD_INDEX_THIRD);
518 
519             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
520             CHECK_NULL_VOID(minuteNode);
521             minuteNode->MovePosition(CHILD_INDEX_SECOND);
522         } else {
523             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
524             CHECK_NULL_VOID(minuteNode);
525             minuteNode->MovePosition(CHILD_INDEX_SECOND);
526         }
527     } else if ((isPreLanguageUg_ && !isAmPmTimeOrderUpdate_) || (language_ == "ug")) {
528         if (hasSecond_) {
529             auto hourNode = host->GetChildAtIndex(CHILD_INDEX_FOURTH);
530             CHECK_NULL_VOID(hourNode);
531             hourNode->MovePosition(CHILD_INDEX_SECOND);
532             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FOURTH);
533             CHECK_NULL_VOID(minuteNode);
534             minuteNode->MovePosition(CHILD_INDEX_THIRD);
535         } else {
536             auto hourNode = host->GetChildAtIndex(CHILD_INDEX_THIRD);
537             CHECK_NULL_VOID(hourNode);
538             hourNode->MovePosition(CHILD_INDEX_SECOND);
539         }
540     }
541     if (isPreLanguageUg_) {
542         isPreLanguageUg_ = false;
543     }
544 }
545 
FlushAmPmFormatString()546 void TimePickerRowPattern::FlushAmPmFormatString()
547 {
548     auto amPmStrings = Localization::GetInstance()->GetAmPmStrings();
549     if (amPmStrings.size() > 1) {
550         vecAmPm_.clear();
551         std::string am = amPmStrings[0];
552         vecAmPm_.emplace_back(am);
553         std::string pm = amPmStrings[1];
554         vecAmPm_.emplace_back(pm);
555     }
556 }
557 
SetChangeCallback(ColumnChangeCallback && value)558 void TimePickerRowPattern::SetChangeCallback(ColumnChangeCallback&& value)
559 {
560     auto host = GetHost();
561     CHECK_NULL_VOID(host);
562     auto children = host->GetChildren();
563     for (const auto& child : children) {
564         auto stackNode = DynamicCast<FrameNode>(child);
565         CHECK_NULL_VOID(stackNode);
566         auto columnBlendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
567         CHECK_NULL_VOID(columnBlendNode);
568         auto childNode = DynamicCast<FrameNode>(columnBlendNode->GetLastChild());
569         CHECK_NULL_VOID(childNode);
570         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
571         CHECK_NULL_VOID(timePickerColumnPattern);
572         timePickerColumnPattern->SetChangeCallback(std::move(value));
573     }
574 }
575 
FlushColumn()576 void TimePickerRowPattern::FlushColumn()
577 {
578     UpdateAllChildNode();
579     auto amPmColumn = allChildNode_["amPm"].Upgrade();
580     auto hourColumn = allChildNode_["hour"].Upgrade();
581     if (GetHour24()) {
582         CHECK_NULL_VOID(hourColumn);
583         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
584         CHECK_NULL_VOID(hourColumnPattern);
585         hourColumnPattern->SetOptions(GetOptionsCount());
586         hourColumnPattern->SetShowCount(GetShowCount());
587         hourColumnPattern->FlushCurrentOptions();
588     } else if (amPmColumn) {
589         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
590         CHECK_NULL_VOID(amPmColumnPattern);
591         amPmColumnPattern->SetShowCount(AM_PM_COUNT);
592         amPmColumnPattern->FlushCurrentOptions();
593 
594         CHECK_NULL_VOID(hourColumn);
595         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
596         CHECK_NULL_VOID(hourColumnPattern);
597         hourColumnPattern->SetOptions(GetOptionsCount());
598         hourColumnPattern->SetShowCount(GetShowCount());
599         hourColumnPattern->FlushCurrentOptions();
600     }
601 
602     auto minuteColumn = allChildNode_["minute"].Upgrade();
603     CHECK_NULL_VOID(minuteColumn);
604     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
605     CHECK_NULL_VOID(minuteColumnPattern);
606     minuteColumnPattern->SetShowCount(GetShowCount());
607     minuteColumnPattern->FlushCurrentOptions();
608     if (hasSecond_) {
609         auto secondColumn = allChildNode_["second"].Upgrade();
610         CHECK_NULL_VOID(secondColumn);
611         auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
612         CHECK_NULL_VOID(secondColumnPattern);
613         secondColumnPattern->SetOptions(GetOptionsCount());
614         secondColumnPattern->SetShowCount(GetShowCount());
615         secondColumnPattern->FlushCurrentOptions();
616     }
617 }
618 
OnDataLinking(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)619 void TimePickerRowPattern::OnDataLinking(
620     const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
621 {
622     CHECK_NULL_VOID(tag);
623     auto hourNode = allChildNode_["hour"].Upgrade();
624     CHECK_NULL_VOID(hourNode);
625     if (tag->GetId() != hourNode->GetId()) {
626         return;
627     }
628 
629     if (!GetHour24()) {
630         HandleHour12Change(isAdd, index, resultTags);
631     }
632 }
633 
GetOptionsValue(const RefPtr<FrameNode> & frameNode,uint32_t optionIndex)634 const std::string& TimePickerRowPattern::GetOptionsValue(const RefPtr<FrameNode>& frameNode, uint32_t optionIndex)
635 {
636     UpdateAllChildNode();
637     if (frameNode == allChildNode_["amPm"]) {
638         return options_[allChildNode_["amPm"]][optionIndex];
639     }
640     bool isHour12 = !GetHour24();
641     auto isHourNode = frameNode == allChildNode_["hour"];
642     if (options_.find(frameNode) == options_.end()) {
643         options_[frameNode] = std::unordered_map<uint32_t, std::string>();
644     }
645     if (options_[frameNode].find(optionIndex) == options_[frameNode].end()) {
646         options_[frameNode][optionIndex] =
647             isHourNode ? GetHourFormatString(optionIndex + isHour12) : GetMinuteFormatString(optionIndex);
648     }
649     return options_[frameNode][optionIndex];
650 }
651 
OnColumnsBuilding()652 void TimePickerRowPattern::OnColumnsBuilding()
653 {
654     HandleHourColumnBuilding();
655     HandleMinAndSecColumnBuilding();
656 }
657 
HandleHourColumnBuilding()658 void TimePickerRowPattern::HandleHourColumnBuilding()
659 {
660     UpdateAllChildNode();
661     auto amPmColumn = allChildNode_["amPm"].Upgrade();
662     auto hourColumn = allChildNode_["hour"].Upgrade();
663     optionsTotalCount_[hourColumn] = 0;
664     if (GetHour24()) {
665         CHECK_NULL_VOID(hourColumn);
666         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
667         CHECK_NULL_VOID(hourColumnPattern);
668         for (uint32_t hour = 0; hour <= 23; ++hour) { // time's hour from 0 to 23.
669             if (hour == selectedTime_.GetHour()) {
670                 hourColumnPattern->SetCurrentIndex(hour);
671             }
672             optionsTotalCount_[hourColumn]++;
673         }
674         hourColumnPattern->SetOptions(GetOptionsCount());
675         hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
676         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
677     } else if (amPmColumn) {
678         CHECK_NULL_VOID(amPmColumn);
679         CHECK_NULL_VOID(hourColumn);
680         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
681         CHECK_NULL_VOID(amPmColumnPattern);
682         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
683         CHECK_NULL_VOID(hourColumnPattern);
684         options_[amPmColumn][0] = GetAmFormatString();
685         options_[amPmColumn][1] = GetPmFormatString();
686 
687         if (IsAmHour(selectedTime_.GetHour())) {
688             amPmColumnPattern->SetCurrentIndex(0); // AM's index
689         } else {
690             amPmColumnPattern->SetCurrentIndex(1); // PM's index
691         }
692         optionsTotalCount_[amPmColumn] = CHILD_WITHOUT_AMPM_SIZE;
693         auto selectedHour = GetAmPmHour(selectedTime_.GetHour());
694         for (uint32_t hour = 1; hour <= AM_PM_HOUR_12; ++hour) { // AM_PM hour start from 1 to 12
695             if (hour == selectedHour) {
696                 hourColumnPattern->SetCurrentIndex(hour - 1);
697             }
698             optionsTotalCount_[hourColumn]++;
699         }
700         amPmColumnPattern->SetOptions(GetOptionsCount());
701         hourColumnPattern->SetOptions(GetOptionsCount());
702         amPmColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
703         hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
704     }
705 }
706 
HandleMinAndSecColumnBuilding()707 void TimePickerRowPattern::HandleMinAndSecColumnBuilding()
708 {
709     UpdateAllChildNode();
710     auto minuteColumn = allChildNode_["minute"].Upgrade();
711     CHECK_NULL_VOID(minuteColumn);
712     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
713     CHECK_NULL_VOID(minuteColumnPattern);
714     optionsTotalCount_[minuteColumn] = 0;
715 
716     for (uint32_t minute = 0; minute <= 59; ++minute) { // time's minute from 0 to 59
717         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
718             GetPrefixMinute() == ZeroPrefixType::HIDE) {
719             options_[minuteColumn][minute] = std::to_string(minute);
720         } else {
721             if (minute < 10) { // time's minute less than 10
722                 options_[minuteColumn][minute] = std::string("0") + std::to_string(minute);
723             }
724         }
725         if (minute == selectedTime_.GetMinute()) {
726             minuteColumnPattern->SetCurrentIndex(minute);
727         }
728         optionsTotalCount_[minuteColumn]++;
729     }
730     minuteColumnPattern->SetOptions(GetOptionsCount());
731     minuteColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
732 
733     auto secondColumn = allChildNode_["second"].Upgrade();
734     CHECK_NULL_VOID(secondColumn);
735     auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
736     CHECK_NULL_VOID(secondColumnPattern);
737     optionsTotalCount_[secondColumn] = 0;
738 
739     for (uint32_t second = 0; second <= 59; ++second) { // time's second from 0 to 59
740         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
741             GetPrefixSecond() == ZeroPrefixType::HIDE) {
742             options_[secondColumn][second] = std::to_string(second);
743         } else {
744             if (second < 10) { // time's second less than 10
745                 options_[secondColumn][second] = std::string("0") + std::to_string(second);
746             }
747         }
748         if (second == selectedTime_.GetSecond()) {
749             secondColumnPattern->SetCurrentIndex(second);
750         }
751         optionsTotalCount_[secondColumn]++;
752     }
753     secondColumnPattern->SetOptions(GetOptionsCount());
754     secondColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
755 }
756 
UpdateAllChildNode()757 void TimePickerRowPattern::UpdateAllChildNode()
758 {
759     if (hasSecond_) {
760         GetAllChildNodeWithSecond();
761         return;
762     }
763     auto host = GetHost();
764     CHECK_NULL_VOID(host);
765     if (GetHour24() && host->GetChildren().size() == CHILD_WITH_AMPM_SIZE) {
766         // if amPmTimeOrder is "10", amPm node is in slot 0, otherwise in slot 2
767         host->RemoveChildAtIndex(amPmTimeOrder_ == "10" ? AMPMDEFAULTPOSITION : AMPM_FORWARD_WITHOUTSECOND);
768         amPmId_.reset();
769         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
770         host->MarkModifyDone();
771     } else if (!GetHour24() && host->GetChildren().size() == CHILD_WITHOUT_AMPM_SIZE) {
772         CreateAmPmNode();
773     }
774     if (GetHour24() && host->GetChildren().size() != CHILD_WITHOUT_AMPM_SIZE) {
775         return;
776     }
777 
778     if (!GetHour24() && host->GetChildren().size() != CHILD_WITH_AMPM_SIZE) {
779         return;
780     }
781     if (language_ == "ug") {
782         UpdateAllChildNodeForUg();
783         return;
784     }
785     auto children = host->GetChildren();
786     auto iter = children.begin();
787     CHECK_NULL_VOID(*iter);
788     auto amPmNode = GetAmPmNode(iter);
789     auto hourNode = GetHourNode(iter);
790     auto minuteNode = GetMinuteNode(iter);
791     allChildNode_["amPm"] = amPmNode;
792     allChildNode_["hour"] = hourNode;
793     allChildNode_["minute"] = minuteNode;
794 }
795 
GetAllChildNodeWithSecond()796 void TimePickerRowPattern::GetAllChildNodeWithSecond()
797 {
798     auto host = GetHost();
799     CHECK_NULL_VOID(host);
800     if (GetHour24() && host->GetChildren().size() == CHILD_WITH_AMPM_SIZE + 1) {
801         host->RemoveChildAtIndex(amPmTimeOrder_ == "10" ? AMPMDEFAULTPOSITION : AMPM_FORWARD_WITHSECOND);
802         amPmId_.reset();
803         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
804         host->MarkModifyDone();
805     } else if (!GetHour24() && host->GetChildren().size() == CHILD_WITHOUT_AMPM_SIZE + 1) {
806         CreateAmPmNode();
807     }
808     if ((GetHour24() && host->GetChildren().size() != CHILD_WITHOUT_AMPM_SIZE + 1) ||
809         (!GetHour24() && host->GetChildren().size() != CHILD_WITH_AMPM_SIZE + 1)) {
810         return;
811     }
812     if (language_ == "ug") {
813         UpdateAllChildNodeForUg();
814         return;
815     }
816     auto children = host->GetChildren();
817     auto iter = children.begin();
818     CHECK_NULL_VOID(*iter);
819     auto amPmNode = GetAmPmNode(iter);
820     auto hourNode = GetHourNode(iter);
821     auto minuteNode = GetMinuteNode(iter);
822     auto secondNode = GetSecondNode(iter);
823     allChildNode_["amPm"] = amPmNode;
824     allChildNode_["hour"] = hourNode;
825     allChildNode_["minute"] = minuteNode;
826     allChildNode_["second"] = secondNode;
827 }
828 
GetAmPmNode(std::list<RefPtr<UINode>>::iterator & iter)829 RefPtr<FrameNode> TimePickerRowPattern::GetAmPmNode(std::list<RefPtr<UINode>>::iterator& iter)
830 {
831     if (GetHour24()) {
832         return nullptr;
833     }
834     auto amPm = (*iter);
835     if (amPmTimeOrder_ == "01") {
836         if (!hasSecond_) {
837             std::advance(iter, AMPM_FORWARD_WITHOUTSECOND);
838             amPm = (*iter);
839             std::advance(iter, AMPM_BACKWARD_WITHOUTSECOND);
840         } else {
841             std::advance(iter, AMPM_FORWARD_WITHSECOND);
842             amPm = (*iter);
843             std::advance(iter, AMPM_BACKWARD_WITHSECOND);
844         }
845     } else {
846         iter++;
847     }
848     CHECK_NULL_RETURN(amPm, nullptr);
849     auto amPmStackNode = DynamicCast<FrameNode>(amPm);
850     auto amPmBlendNode = DynamicCast<FrameNode>(amPmStackNode->GetLastChild());
851     CHECK_NULL_RETURN(amPmBlendNode, nullptr);
852     auto amPmNode = DynamicCast<FrameNode>(amPmBlendNode->GetLastChild());
853     CHECK_NULL_RETURN(amPmNode, nullptr);
854     return amPmNode;
855 }
856 
GetHourNode(std::list<RefPtr<UINode>>::iterator & iter)857 RefPtr<FrameNode> TimePickerRowPattern::GetHourNode(std::list<RefPtr<UINode>>::iterator& iter)
858 {
859     auto hour = *iter;
860     CHECK_NULL_RETURN(hour, nullptr);
861     auto hourStackNode = DynamicCast<FrameNode>(hour);
862     auto hourBlendNode = DynamicCast<FrameNode>(hourStackNode->GetLastChild());
863     CHECK_NULL_RETURN(hourBlendNode, nullptr);
864     auto hourNode = DynamicCast<FrameNode>(hourBlendNode->GetLastChild());
865     CHECK_NULL_RETURN(hourNode, nullptr);
866     iter++;
867     return hourNode;
868 }
869 
GetMinuteNode(std::list<RefPtr<UINode>>::iterator & iter)870 RefPtr<FrameNode> TimePickerRowPattern::GetMinuteNode(std::list<RefPtr<UINode>>::iterator& iter)
871 {
872     auto minute = *iter;
873     CHECK_NULL_RETURN(minute, nullptr);
874     auto minuteStackNode = DynamicCast<FrameNode>(minute);
875     auto minuteBlendNode = DynamicCast<FrameNode>(minuteStackNode->GetLastChild());
876     CHECK_NULL_RETURN(minuteBlendNode, nullptr);
877     auto minuteNode = DynamicCast<FrameNode>(minuteBlendNode->GetLastChild());
878     CHECK_NULL_RETURN(minuteNode, nullptr);
879     iter++;
880     return minuteNode;
881 }
882 
GetSecondNode(std::list<RefPtr<UINode>>::iterator & iter)883 RefPtr<FrameNode> TimePickerRowPattern::GetSecondNode(std::list<RefPtr<UINode>>::iterator& iter)
884 {
885     if (!hasSecond_) {
886         return nullptr;
887     }
888     auto second = *iter;
889     CHECK_NULL_RETURN(second, nullptr);
890     auto secondStackNode = DynamicCast<FrameNode>(second);
891     auto secondBlendNode = DynamicCast<FrameNode>(secondStackNode->GetLastChild());
892     CHECK_NULL_RETURN(secondBlendNode, nullptr);
893     auto secondNode = DynamicCast<FrameNode>(secondBlendNode->GetLastChild());
894     CHECK_NULL_RETURN(secondNode, nullptr);
895     if (language_ == "ug") {
896         iter++;
897     }
898     return secondNode;
899 }
900 
UpdateAllChildNodeForUg()901 void TimePickerRowPattern::UpdateAllChildNodeForUg()
902 {
903     auto host = GetHost();
904     CHECK_NULL_VOID(host);
905     auto children = host->GetChildren();
906     auto iter = children.begin();
907     CHECK_NULL_VOID(*iter);
908     RefPtr<FrameNode> amPmNode;
909     if (!GetHour24()) {
910         auto amPm = (*iter);
911         CHECK_NULL_VOID(amPm);
912         auto amPmStackNode = DynamicCast<FrameNode>(amPm);
913         amPmNode = DynamicCast<FrameNode>(amPmStackNode->GetLastChild()->GetLastChild());
914         CHECK_NULL_VOID(amPmNode);
915         iter++;
916     }
917     auto secondNode = GetSecondNode(iter);
918     auto minuteNode = GetMinuteNode(iter);
919     auto hourNode = GetHourNode(iter);
920     allChildNode_["amPm"] = amPmNode;
921     allChildNode_["hour"] = hourNode;
922     allChildNode_["minute"] = minuteNode;
923     allChildNode_["second"] = secondNode;
924 }
925 
HandleHour12Change(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)926 void TimePickerRowPattern::HandleHour12Change(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
927 {
928     UpdateAllChildNode();
929     auto amPm = allChildNode_["amPm"].Upgrade();
930     CHECK_NULL_VOID(amPm);
931     auto amPmPickerColumnPattern = amPm->GetPattern<TimePickerColumnPattern>();
932 
933     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && isAdd && index == 11) { // hour index start from 0 to 11
934         amPmPickerColumnPattern->SetCurrentIndex(1);                               // add to PM's index
935         resultTags.emplace_back(amPm);
936         return;
937     }
938     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && !isAdd && index == 10) { // reduce to 11 hour (index is 10)
939         amPmPickerColumnPattern->SetCurrentIndex(0);                                // change to AM whose index is 0
940         resultTags.emplace_back(amPm);
941         return;
942     }
943     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && isAdd && index == 11) {
944         amPmPickerColumnPattern->SetCurrentIndex(0); // is PM (index is 1) and last hour (index is 11)
945         resultTags.emplace_back(amPm);               // change to PM (index is 0)
946         return;
947     }
948     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && !isAdd && index == 10) { // reduce to 11 hour(index is 10)
949         amPmPickerColumnPattern->SetCurrentIndex(1);                                // change to PM
950         resultTags.emplace_back(amPm);
951         return;
952     }
953 }
954 
GetAmPmHour(uint32_t hourOf24) const955 uint32_t TimePickerRowPattern::GetAmPmHour(uint32_t hourOf24) const
956 {
957     if (hourOf24 == 0) {
958         return AM_PM_HOUR_12;                         // AM 12:00 means 00:00 in 24 hour style
959     }
960     if (1 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11) { // 00:00 to 11:00 is the same for any hour style
961         return hourOf24;
962     }
963     if (hourOf24 == AM_PM_HOUR_12) { // 12:00 means PM start hour
964         return AM_PM_HOUR_12;        // 12 PM
965     }                                // hour from 13 to 23
966     return hourOf24 - AM_PM_HOUR_12; // need reduce 12 to 12 hours style
967 }
968 
IsAmHour(uint32_t hourOf24) const969 bool TimePickerRowPattern::IsAmHour(uint32_t hourOf24) const
970 {
971     return (0 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11); // 00:00 to 11:00 is AM hour
972 }
973 
GetAmFormatString() const974 std::string TimePickerRowPattern::GetAmFormatString() const
975 {
976     if (vecAmPm_.empty()) {
977         return "AM";
978     }
979     return vecAmPm_[0]; // first index is AM
980 }
981 
GetPmFormatString() const982 std::string TimePickerRowPattern::GetPmFormatString() const
983 {
984     if (vecAmPm_.size() < 2) { // size need to be 2 for AM and PM
985         return "PM";
986     }
987     return vecAmPm_[1]; // second index is PM
988 }
989 
GetHourFormatString(uint32_t hour) const990 std::string TimePickerRowPattern::GetHourFormatString(uint32_t hour) const
991 {
992     DateTime time;
993     time.minute = hour; // minute range [0, 59], hour range [0, 23]; hour range is in minute range.
994     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
995         if (Localization::GetInstance()->HasZeroHour()) {
996             return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
997         }
998     } else {
999         if (((GetPrefixHour() == ZeroPrefixType::AUTO) && GetHour24()) ||
1000             GetPrefixHour() == ZeroPrefixType::SHOW) {
1001             return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
1002         }
1003     }
1004     return Localization::GetInstance()->FormatDateTime(time, "m");
1005 }
1006 
GetMinuteFormatString(uint32_t minute) const1007 std::string TimePickerRowPattern::GetMinuteFormatString(uint32_t minute) const
1008 {
1009     DateTime time;
1010     time.minute = minute;
1011     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1012         return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
1013     } else {
1014         return Localization::GetInstance()->FormatDateTime(time, "m");
1015     }
1016 }
1017 
GetSecondFormatString(uint32_t second) const1018 std::string TimePickerRowPattern::GetSecondFormatString(uint32_t second) const
1019 {
1020     DateTime time;
1021     time.second = second;
1022     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1023         return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "s"));
1024     } else {
1025         return Localization::GetInstance()->FormatDateTime(time, "s");
1026     }
1027 }
1028 
AddZeroPrefix(const std::string & value) const1029 std::string TimePickerRowPattern::AddZeroPrefix(const std::string& value) const
1030 {
1031     if (value.size() == 1 && '0' <= value[0] && value[0] <= '9') { // value is number in range [0, 9]
1032         return std::string("0") + value;                           // add prefix '0'
1033     }
1034     return value;
1035 }
1036 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1037 void TimePickerRowPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1038 {
1039     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1040         auto pattern = wp.Upgrade();
1041         if (pattern) {
1042             return pattern->OnKeyEvent(event);
1043         }
1044         return false;
1045     };
1046     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1047 
1048     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
1049         auto pattern = wp.Upgrade();
1050         if (pattern) {
1051             pattern->GetInnerFocusPaintRect(paintRect);
1052         }
1053     };
1054     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1055 }
1056 
PaintFocusState()1057 void TimePickerRowPattern::PaintFocusState()
1058 {
1059     auto host = GetHost();
1060     CHECK_NULL_VOID(host);
1061 
1062     RoundRect focusRect;
1063     GetInnerFocusPaintRect(focusRect);
1064 
1065     auto focusHub = host->GetFocusHub();
1066     CHECK_NULL_VOID(focusHub);
1067     focusHub->PaintInnerFocusState(focusRect);
1068 
1069     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1070 }
1071 
GetInnerFocusPaintRect(RoundRect & paintRect)1072 void TimePickerRowPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
1073 {
1074     auto host = GetHost();
1075     CHECK_NULL_VOID(host);
1076     auto childSize = host->GetChildren().size();
1077     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
1078     CHECK_NULL_VOID(stackChild);
1079     auto columnBlendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
1080     CHECK_NULL_VOID(columnBlendChild);
1081     auto pickerChild = DynamicCast<FrameNode>(columnBlendChild->GetLastChild());
1082     CHECK_NULL_VOID(pickerChild);
1083     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
1084     auto pipeline = PipelineBase::GetCurrentContext();
1085     CHECK_NULL_VOID(pipeline);
1086     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
1087     CHECK_NULL_VOID(pickerTheme);
1088     auto frameWidth = host->GetGeometryNode()->GetFrameSize().Width();
1089     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
1090     auto pickerThemeWidth = dividerSpacing * RATE;
1091 
1092     CHECK_EQUAL_VOID(childSize, 0);
1093     auto centerX = (frameWidth / childSize - pickerThemeWidth) / RATE +
1094                    pickerChild->GetGeometryNode()->GetFrameRect().Width() * focusKeyID_ +
1095                    PRESS_INTERVAL.ConvertToPx() * RATE;
1096     CHECK_NULL_VOID(host->GetGeometryNode());
1097     auto centerY =
1098         (host->GetGeometryNode()->GetFrameSize().Height() - dividerSpacing) / RATE + PRESS_INTERVAL.ConvertToPx();
1099     float piantRectWidth = (dividerSpacing - PRESS_INTERVAL.ConvertToPx()) * RATE;
1100     float piantRectHeight = dividerSpacing - PRESS_INTERVAL.ConvertToPx() * RATE;
1101     if (piantRectWidth > columnWidth) {
1102         piantRectWidth = columnWidth - FOCUS_OFFSET.ConvertToPx() * RATE;
1103         centerX = focusKeyID_ * columnWidth + FOCUS_OFFSET.ConvertToPx();
1104     }
1105     paintRect.SetRect(RectF(centerX, centerY, piantRectWidth, piantRectHeight));
1106     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
1107         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
1108     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
1109         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
1110     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
1111         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
1112     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
1113         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
1114 }
1115 
OnKeyEvent(const KeyEvent & event)1116 bool TimePickerRowPattern::OnKeyEvent(const KeyEvent& event)
1117 {
1118     if (event.action != KeyAction::DOWN) {
1119         return false;
1120     }
1121     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
1122         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
1123         event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
1124         return HandleDirectionKey(event.code);
1125     }
1126     return false;
1127 }
1128 
SetFocusDisable()1129 void TimePickerRowPattern::SetFocusDisable()
1130 {
1131     auto host = GetHost();
1132     CHECK_NULL_VOID(host);
1133 
1134     auto focusHub = host->GetFocusHub();
1135     CHECK_NULL_VOID(focusHub);
1136 
1137     focusHub->SetFocusable(false);
1138 }
1139 
SetFocusEnable()1140 void TimePickerRowPattern::SetFocusEnable()
1141 {
1142     auto host = GetHost();
1143     CHECK_NULL_VOID(host);
1144 
1145     auto focusHub = host->GetFocusHub();
1146     CHECK_NULL_VOID(focusHub);
1147 
1148     focusHub->SetFocusable(true);
1149 }
1150 
HandleDirectionKey(KeyCode code)1151 bool TimePickerRowPattern::HandleDirectionKey(KeyCode code)
1152 {
1153     auto host = GetHost();
1154     CHECK_NULL_RETURN(host, false);
1155     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
1156     auto childSize = host->GetChildren().size();
1157     auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild()->GetLastChild());
1158     auto pattern = pickerChild->GetPattern<TimePickerColumnPattern>();
1159     auto currentIndex = pattern->GetCurrentIndex();
1160     auto totalOptionCount = GetOptionCount(pickerChild);
1161     if (totalOptionCount == 0) {
1162         return false;
1163     }
1164     if (code == KeyCode::KEY_DPAD_UP || code == KeyCode::KEY_DPAD_DOWN) {
1165         auto index = (code == KeyCode::KEY_DPAD_UP) ? -1 : 1;
1166         pattern->SetCurrentIndex((totalOptionCount + currentIndex + index) % totalOptionCount);
1167         pattern->FlushCurrentOptions();
1168         pattern->HandleChangeCallback((code == KeyCode::KEY_DPAD_UP) ? false : true, true);
1169         pattern->HandleEventCallback(true);
1170         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1171         return true;
1172     }
1173     if (code == KeyCode::KEY_MOVE_HOME) {
1174         pattern->SetCurrentIndex(1);
1175         pattern->InnerHandleScroll(false, false);
1176         return true;
1177     }
1178     if (code == KeyCode::KEY_MOVE_END) {
1179         pattern->SetCurrentIndex(totalOptionCount - UNOPTION_COUNT);
1180         pattern->InnerHandleScroll(true, false);
1181         return true;
1182     }
1183     if (code == KeyCode::KEY_DPAD_LEFT) {
1184         focusKeyID_ -= 1;
1185         if (focusKeyID_ < 0) {
1186             focusKeyID_ = 0;
1187             return false;
1188         }
1189         PaintFocusState();
1190         return true;
1191     }
1192     if (code == KeyCode::KEY_DPAD_RIGHT) {
1193         focusKeyID_ += 1;
1194         if (focusKeyID_ > static_cast<int32_t>(childSize) - 1) {
1195             focusKeyID_ = static_cast<int32_t>(childSize) - 1;
1196             return false;
1197         }
1198         PaintFocusState();
1199         return true;
1200     }
1201     return false;
1202 }
1203 
OnColorConfigurationUpdate()1204 void TimePickerRowPattern::OnColorConfigurationUpdate()
1205 {
1206     auto host = GetHost();
1207     CHECK_NULL_VOID(host);
1208     host->SetNeedCallChildrenUpdate(false);
1209     auto context = host->GetContext();
1210     CHECK_NULL_VOID(context);
1211     auto pickerTheme = context->GetTheme<PickerTheme>();
1212     CHECK_NULL_VOID(pickerTheme);
1213     auto dialogTheme = context->GetTheme<DialogTheme>();
1214     CHECK_NULL_VOID(dialogTheme);
1215     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
1216     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
1217     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
1218     CHECK_NULL_VOID(pickerProperty);
1219     pickerProperty->UpdateColor(GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
1220     pickerProperty->UpdateDisappearColor(
1221         GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
1222     if (isPicker_) {
1223         return;
1224     }
1225     SetBackgroundColor(dialogTheme->GetBackgroundColor());
1226     auto buttonTitleNode = buttonTitleNode_.Upgrade();
1227     CHECK_NULL_VOID(buttonTitleNode);
1228     auto buttonTitleRenderContext = buttonTitleNode->GetRenderContext();
1229     CHECK_NULL_VOID(buttonTitleRenderContext);
1230     buttonTitleRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
1231     auto childText = buttonTitleNode->GetFirstChild();
1232     CHECK_NULL_VOID(childText);
1233     auto textTitleNode = DynamicCast<FrameNode>(childText);
1234     CHECK_NULL_VOID(textTitleNode);
1235     auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
1236     CHECK_NULL_VOID(textLayoutProperty);
1237     textLayoutProperty->UpdateTextColor(pickerTheme->GetTitleStyle().GetTextColor());
1238     auto contentRowNode = contentRowNode_.Upgrade();
1239     CHECK_NULL_VOID(contentRowNode);
1240     auto layoutRenderContext = contentRowNode->GetRenderContext();
1241     CHECK_NULL_VOID(layoutRenderContext);
1242     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) || !layoutRenderContext->IsUniRenderEnabled()) {
1243         layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
1244     }
1245     host->MarkModifyDone();
1246 }
1247 } // namespace OHOS::Ace::NG
1248