• 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 constexpr uint32_t MINUTE_10 = 10;
36 const int32_t AM_PM_COUNT = 3;
37 const Dimension PRESS_INTERVAL = 4.0_vp;
38 const Dimension PRESS_RADIUS = 8.0_vp;
39 const int32_t UNOPTION_COUNT = 2;
40 const int32_t AMPMDEFAULTPOSITION = 0;
41 const int32_t AMPM_FORWARD_WITHSECOND = 3;
42 const int32_t AMPM_FORWARD_WITHOUTSECOND = 2;
43 const int32_t AMPM_BACKWARD_WITHSECOND = -3;
44 const int32_t AMPM_BACKWARD_WITHOUTSECOND = -2;
45 const int32_t CHILD_INDEX_FIRST = 0;
46 const int32_t CHILD_INDEX_SECOND = 1;
47 const int32_t CHILD_INDEX_THIRD = 2;
48 const int32_t CHILD_INDEX_FOURTH = 3;
49 constexpr float DISABLE_ALPHA = 0.6f;
50 const Dimension FOCUS_INTERVAL = 2.0_vp;
51 const Dimension LINE_WIDTH = 1.5_vp;
52 const int32_t RATE = 2;
53 const PickerTime START_DEFAULT_TIME = PickerTime(0, 0, 0);
54 const PickerTime END_DEFAULT_TIME = PickerTime(23, 59, 59);
55 const uint32_t INDEX_AM_0 = 0;
56 const uint32_t INDEX_PM_1 = 1;
57 const uint32_t INDEX_HOUR_STRAT = 0;
58 const uint32_t INDEX_MINUTE_STRAT = 0;
59 const uint32_t INDEX_MINUTE_END = 59;
60 const uint32_t INDEX_SECOND_STRAT = 0;
61 const uint32_t INDEX_SECOND_ADD_ZERO = 10;
62 const uint32_t INDEX_SECOND_END = 59;
63 const uint32_t SIZE_OF_AMPM_COLUMN_OPTION = 2;
64 } // namespace
65 
OnAttachToFrameNode()66 void TimePickerRowPattern::OnAttachToFrameNode()
67 {
68     auto host = GetHost();
69     CHECK_NULL_VOID(host);
70     host->GetRenderContext()->SetClipToFrame(true);
71     host->GetRenderContext()->UpdateClipEdge(true);
72 }
73 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)74 bool TimePickerRowPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
75 {
76     CHECK_NULL_RETURN(dirty, false);
77     SetButtonIdeaSize();
78     return true;
79 }
80 
SetButtonIdeaSize()81 void TimePickerRowPattern::SetButtonIdeaSize()
82 {
83     auto host = GetHost();
84     CHECK_NULL_VOID(host);
85     auto context = host->GetContext();
86     CHECK_NULL_VOID(context);
87     auto pickerTheme = context->GetTheme<PickerTheme>();
88     CHECK_NULL_VOID(pickerTheme);
89     auto children = host->GetChildren();
90     auto height = pickerTheme->GetDividerSpacing();
91     for (const auto& child : children) {
92         auto childNode = DynamicCast<FrameNode>(child);
93         CHECK_NULL_VOID(childNode);
94         auto width = childNode->GetGeometryNode()->GetFrameSize().Width();
95         auto defaultWidth = height.ConvertToPx() * 2;
96         if (width > defaultWidth) {
97             width = static_cast<float>(defaultWidth);
98         }
99         auto timePickerColumnNode = DynamicCast<FrameNode>(childNode->GetLastChild());
100         CHECK_NULL_VOID(timePickerColumnNode);
101         auto columnNodeHeight = timePickerColumnNode->GetGeometryNode()->GetFrameSize().Height();
102         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
103         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
104         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
105         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
106         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
107         auto standardButtonHeight = static_cast<float>((height - PRESS_INTERVAL).ConvertToPx());
108         auto maxButtonHeight = static_cast<float>(columnNodeHeight);
109         auto buttonHeight = Dimension(std::min(standardButtonHeight, maxButtonHeight), DimensionUnit::PX);
110         buttonLayoutProperty->UpdateUserDefinedIdealSize(
111             CalcSize(CalcLength(width - PRESS_INTERVAL.ConvertToPx()), CalcLength(buttonHeight)));
112         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
113         buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
114         buttonNode->MarkModifyDone();
115         buttonNode->MarkDirtyNode();
116         if (GetIsShowInDialog() && GreatNotEqual(standardButtonHeight, maxButtonHeight) &&
117             GreatNotEqual(maxButtonHeight, 0.0f)) {
118             auto parentNode = DynamicCast<FrameNode>(host->GetParent());
119             CHECK_NULL_VOID(parentNode);
120             parentNode->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
121         }
122     }
123 }
124 
ColumnPatternInitHapticController()125 void TimePickerRowPattern::ColumnPatternInitHapticController()
126 {
127     if (!isHapticChanged_) {
128         return;
129     }
130 
131     isHapticChanged_ = false;
132     for (auto iter = allChildNode_.begin(); iter != allChildNode_.end(); iter++) {
133         auto columnNode = iter->second.Upgrade();
134         if (!columnNode) {
135             continue;
136         }
137         auto pattern = columnNode->GetPattern<TimePickerColumnPattern>();
138         if (!pattern) {
139             continue;
140         }
141         pattern->InitHapticController(columnNode);
142     }
143 }
144 
ColumnPatternStopHaptic()145 void TimePickerRowPattern::ColumnPatternStopHaptic()
146 {
147     if (!isEnableHaptic_) {
148         return;
149     }
150     for (auto iter = allChildNode_.begin(); iter != allChildNode_.end(); iter++) {
151         auto columnNode = iter->second.Upgrade();
152         if (!columnNode) {
153             continue;
154         }
155         auto timePickerColumnPattern = columnNode->GetPattern<TimePickerColumnPattern>();
156         if (!timePickerColumnPattern) {
157             continue;
158         }
159         timePickerColumnPattern->StopHaptic();
160     }
161 }
162 
IsCircle()163 bool TimePickerRowPattern::IsCircle()
164 {
165     auto host = GetHost();
166     CHECK_NULL_RETURN(host, false);
167     auto context = host->GetContext();
168     CHECK_NULL_RETURN(context, false);
169     auto pickerTheme = context->GetTheme<PickerTheme>();
170     CHECK_NULL_RETURN(pickerTheme, false);
171 
172     return pickerTheme->IsCircleDial();
173 }
174 
SetDefaultColoumnFocus(std::unordered_map<std::string,WeakPtr<FrameNode>>::iterator & it,const std::string & id,bool & focus,const std::function<void (const std::string &)> & call)175 void TimePickerRowPattern::SetDefaultColoumnFocus(std::unordered_map<std::string, WeakPtr<FrameNode>>::iterator& it,
176     const std::string &id, bool& focus, const std::function<void(const std::string&)>& call)
177 {
178     auto column = it->second.Upgrade();
179     CHECK_NULL_VOID(column);
180     auto tmpPattern = column->GetPattern<TimePickerColumnPattern>();
181     CHECK_NULL_VOID(tmpPattern);
182     tmpPattern->SetSelectedMarkId(id);
183     tmpPattern->SetSelectedMarkListener(call);
184     if (focus) {
185         tmpPattern->SetSelectedMark(true, false);
186         selectedColumnId_ = id;
187         focus = false;
188     }
189 }
190 
ClearFocus()191 void TimePickerRowPattern::ClearFocus()
192 {
193     CHECK_EQUAL_VOID(IsCircle(), false);
194     if (!isClearFocus_ && (HasSecondNode() == hasSecond_)) {
195         return ;
196     }
197     isClearFocus_ = true;
198     if (!selectedColumnId_.empty()) {
199         auto it = allChildNode_.find(selectedColumnId_);
200         if (it != allChildNode_.end()) {
201             auto column = it->second.Upgrade();
202             CHECK_NULL_VOID(column);
203             auto tmpPattern = column->GetPattern<TimePickerColumnPattern>();
204             CHECK_NULL_VOID(tmpPattern);
205             tmpPattern->SetSelectedMark(false, false);
206         }
207 
208         selectedColumnId_ = "";
209     }
210 }
211 
SetDefaultFocus()212 void TimePickerRowPattern::SetDefaultFocus()
213 {
214     CHECK_EQUAL_VOID(IsCircle(), false);
215     CHECK_EQUAL_VOID(isClearFocus_, false);
216     isClearFocus_ = false;
217     std::function<void(const std::string &focusId)> call =  [weak = WeakClaim(this)](const std::string &focusId) {
218         auto pattern = weak.Upgrade();
219         CHECK_NULL_VOID(pattern);
220         if (pattern->selectedColumnId_.empty()) {
221             pattern->selectedColumnId_ = focusId;
222             return;
223         }
224         auto it = pattern->allChildNode_.find(pattern->selectedColumnId_);
225         if (it != pattern->allChildNode_.end()) {
226             auto tmpColumn = it->second.Upgrade();
227             if (tmpColumn) {
228                 auto tmpPattern = tmpColumn->GetPattern<TimePickerColumnPattern>();
229                 CHECK_NULL_VOID(tmpPattern);
230                 tmpPattern->SetSelectedMark(false, false);
231             }
232         }
233         pattern->selectedColumnId_ = focusId;
234     };
235     static const std::string columnName[] = {"amPm", "hour", "minute", "second"};
236     bool setFocus = true;
237     for (size_t i = 0; i < sizeof(columnName) / sizeof(columnName[0]); i++) {
238         auto it = allChildNode_.find(columnName[i]);
239         if (it != allChildNode_.end()) {
240             SetDefaultColoumnFocus(it, columnName[i], setFocus, call);
241         }
242     }
243 }
244 
245 #ifdef SUPPORT_DIGITAL_CROWN
InitOnCrownEvent(const RefPtr<FocusHub> & focusHub)246 void TimePickerRowPattern::InitOnCrownEvent(const RefPtr<FocusHub>& focusHub)
247 {
248     CHECK_NULL_VOID(focusHub);
249     auto onCrowEvent = [wp = WeakClaim(this)](const CrownEvent& event) -> bool {
250         auto pattern = wp.Upgrade();
251         CHECK_NULL_RETURN(pattern, false);
252         return pattern->OnCrownEvent(event);
253     };
254     focusHub->SetOnCrownEventInternal(std::move(onCrowEvent));
255 }
256 
OnCrownEvent(const CrownEvent & event)257 bool TimePickerRowPattern::OnCrownEvent(const CrownEvent& event)
258 {
259     if (event.action == OHOS::Ace::CrownAction::BEGIN ||
260         event.action == OHOS::Ace::CrownAction::UPDATE ||
261         event.action == OHOS::Ace::CrownAction::END) {
262         RefPtr<TimePickerColumnPattern> crownPickerColumnPattern;
263         for (auto& iter : timePickerColumns_) {
264             auto column = iter.Upgrade();
265             if (!column) {
266                 continue;
267             }
268             auto pickerColumnPattern = column->GetPattern<TimePickerColumnPattern>();
269             CHECK_NULL_RETURN(pickerColumnPattern, false);
270             auto columnID =  pickerColumnPattern->GetSelectedColumnId();
271             if (!pickerColumnPattern->IsCrownEventEnded()) {
272                 crownPickerColumnPattern = pickerColumnPattern;
273                 break;
274             } else if (columnID == selectedColumnId_) {
275                 crownPickerColumnPattern = pickerColumnPattern;
276             }
277         }
278         if (crownPickerColumnPattern != nullptr) {
279             return crownPickerColumnPattern->OnCrownEvent(event);
280         }
281     }
282     return false;
283 }
284 #endif
285 
InitFocusEvent()286 void TimePickerRowPattern::InitFocusEvent()
287 {
288     auto host = GetHost();
289     CHECK_NULL_VOID(host);
290     auto focusHub = host->GetFocusHub();
291     if (focusHub) {
292         InitOnKeyEvent(focusHub);
293 #ifdef SUPPORT_DIGITAL_CROWN
294         InitOnCrownEvent(focusHub);
295 #endif
296     }
297 }
298 
UpdateTitleNodeContent()299 void TimePickerRowPattern::UpdateTitleNodeContent()
300 {
301     if (HasTitleNode()) {
302         auto textTitleNode = FrameNode::GetOrCreateFrameNode(
303             V2::TEXT_ETS_TAG, GetTitleId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
304         auto str = GetDialogTitleDate();
305         CHECK_NULL_VOID(textTitleNode);
306         auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
307         CHECK_NULL_VOID(textLayoutProperty);
308         textLayoutProperty->UpdateContent(str.ToString(false));
309     }
310 }
311 
SetCallBack()312 void TimePickerRowPattern::SetCallBack()
313 {
314     SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag, bool add, uint32_t index, bool notify) {
315         auto refPtr = weak.Upgrade();
316         CHECK_NULL_VOID(refPtr);
317         refPtr->HandleColumnChange(tag, add, index, notify);
318     });
319     SetEventCallback([weak = WeakClaim(this)](bool refresh) {
320         auto refPtr = weak.Upgrade();
321         CHECK_NULL_VOID(refPtr);
322         refPtr->FireChangeEvent(refresh);
323     });
324     SetEnterSelectedAreaEventCallback([weak = WeakClaim(this)](bool refresh) {
325         auto refPtr = weak.Upgrade();
326         CHECK_NULL_VOID(refPtr);
327         refPtr->FireEnterSelectedAreaEvent(refresh);
328     });
329 }
330 
OnModifyDone()331 void TimePickerRowPattern::OnModifyDone()
332 {
333     Pattern::CheckLocalized();
334     if (isFiredTimeChange_ && !isForceUpdate_ && !isDateTimeOptionUpdate_) {
335         isFiredTimeChange_ = false;
336         ColumnPatternInitHapticController();
337         return;
338     }
339     LimitSelectedTimeInRange();
340     isHapticChanged_ = false;
341     isForceUpdate_ = false;
342     isDateTimeOptionUpdate_ = false;
343     ClearFocus();
344     auto host = GetHost();
345     CHECK_NULL_VOID(host);
346     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
347     CHECK_NULL_VOID(pickerProperty);
348     wheelModeEnabled_ = pickerProperty->GetLoopValue(true);
349     UpdateLanguageAndAmPmTimeOrder();
350     CreateOrDeleteSecondNode();
351     CreateAmPmNode();
352     OnColumnsBuilding();
353     FlushColumn();
354     InitDisabled();
355     SetCallBack();
356     InitFocusEvent();
357     UpdateTitleNodeContent();
358     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
359     if (isUserSetSelectColor_) {
360         UpdateUserSetSelectColor();
361     }
362     SetDefaultFocus();
363 }
364 
LimitSelectedTimeInRange()365 void TimePickerRowPattern::LimitSelectedTimeInRange()
366 {
367     if (IsStartEndTimeDefined()) {
368         selectedTime_ = AdjustTime(selectedTime_);
369     }
370 }
371 
InitDisabled()372 void TimePickerRowPattern::InitDisabled()
373 {
374     auto host = GetHost();
375     CHECK_NULL_VOID(host);
376     auto eventHub = host->GetEventHub<EventHub>();
377     CHECK_NULL_VOID(eventHub);
378     enabled_ = eventHub->IsEnabled();
379     auto renderContext = host->GetRenderContext();
380     CHECK_NULL_VOID(renderContext);
381     auto opacity = curOpacity_;
382     if (!enabled_) {
383         opacity *= DISABLE_ALPHA;
384         renderContext->UpdateOpacity(opacity);
385     } else if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
386         renderContext->UpdateOpacity(opacity);
387     }
388 
389     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
390         for (const auto& child : host->GetChildren()) {
391             auto stackNode = DynamicCast<FrameNode>(child);
392             CHECK_NULL_VOID(stackNode);
393             auto renderContext = stackNode->GetRenderContext();
394             CHECK_NULL_VOID(renderContext);
395             renderContext->UpdateOpacity(opacity);
396         }
397     }
398     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
399 }
400 
CreateAmPmNode()401 void TimePickerRowPattern::CreateAmPmNode()
402 {
403     auto host = GetHost();
404     CHECK_NULL_VOID(host);
405     auto context = host->GetContext();
406     CHECK_NULL_VOID(context);
407     auto pickerTheme = context->GetTheme<PickerTheme>();
408     CHECK_NULL_VOID(pickerTheme);
409     auto height = pickerTheme->GetDividerSpacing();
410     if (!GetHour24() && !HasAmPmNode()) {
411         auto amPmColumnNode = FrameNode::GetOrCreateFrameNode(
412             V2::COLUMN_ETS_TAG, GetAmPmId(), []() { return AceType::MakeRefPtr<TimePickerColumnPattern>(); });
413         CHECK_NULL_VOID(amPmColumnNode);
414         for (uint32_t index = 0; index < AM_PM_COUNT; index++) {
415             auto textNode = FrameNode::CreateFrameNode(
416                 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
417             CHECK_NULL_VOID(textNode);
418             textNode->MountToParent(amPmColumnNode);
419         }
420         SetColumn(amPmColumnNode);
421         auto stackAmPmNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
422             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
423         auto buttonNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
424             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
425         auto blendNodeId = ElementRegister::GetInstance()->MakeUniqueId();
426         auto columnBlendNode = FrameNode::GetOrCreateFrameNode(
427             V2::COLUMN_ETS_TAG, blendNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
428         buttonNode->MountToParent(stackAmPmNode);
429         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
430         amPmColumnNode->MountToParent(columnBlendNode);
431         columnBlendNode->MountToParent(stackAmPmNode);
432         auto layoutProperty = stackAmPmNode->GetLayoutProperty<LayoutProperty>();
433         layoutProperty->UpdateAlignment(Alignment::CENTER);
434         layoutProperty->UpdateLayoutWeight(1);
435         amPmTimeOrder_ == "01" ? stackAmPmNode->MountToParent(host) : stackAmPmNode->MountToParent(host, 0);
436         if (SetAmPmButtonIdeaSize() > 0) {
437             auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
438             buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
439             buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
440             buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
441             buttonLayoutProperty->UpdateUserDefinedIdealSize(
442                 CalcSize(CalcLength(SetAmPmButtonIdeaSize()), CalcLength(height - PRESS_INTERVAL)));
443             buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
444             buttonNode->MarkModifyDone();
445             buttonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
446         }
447         host->MarkModifyDone();
448         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
449     }
450 }
451 
CreateOrDeleteSecondNode()452 void TimePickerRowPattern::CreateOrDeleteSecondNode()
453 {
454     auto host = GetHost();
455     CHECK_NULL_VOID(host);
456     if (!HasSecondNode()) {
457         if (hasSecond_) {
458             auto secondColumnNode = FrameNode::GetOrCreateFrameNode(
459                 V2::COLUMN_ETS_TAG, GetSecondId(), []() { return AceType::MakeRefPtr<TimePickerColumnPattern>(); });
460             CHECK_NULL_VOID(secondColumnNode);
461             for (uint32_t index = 0; index < GetShowCount(); index++) {
462                 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG,
463                     ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
464                 CHECK_NULL_VOID(textNode);
465                 textNode->MarkModifyDone();
466                 textNode->MountToParent(secondColumnNode);
467             }
468             SetColumn(secondColumnNode);
469             auto stackSecondNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
470                 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
471             auto buttonSecondNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
472                 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
473             auto blendNodeId = ElementRegister::GetInstance()->MakeUniqueId();
474             auto columnBlendNode = FrameNode::GetOrCreateFrameNode(
475                 V2::COLUMN_ETS_TAG, blendNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(true); });
476             buttonSecondNode->MarkModifyDone();
477             buttonSecondNode->MountToParent(stackSecondNode);
478             secondColumnNode->MarkModifyDone();
479             secondColumnNode->MountToParent(columnBlendNode);
480             columnBlendNode->MarkModifyDone();
481             columnBlendNode->MountToParent(stackSecondNode);
482             auto layoutProperty = stackSecondNode->GetLayoutProperty<LayoutProperty>();
483             layoutProperty->UpdateAlignment(Alignment::CENTER);
484             layoutProperty->UpdateLayoutWeight(1);
485             stackSecondNode->MarkModifyDone();
486             MountSecondNode(stackSecondNode);
487             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
488         }
489     } else {
490         if (!hasSecond_) {
491             RemoveSecondNode();
492             secondId_.reset();
493             host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
494         }
495     }
496 }
497 
MountSecondNode(const RefPtr<FrameNode> & stackSecondNode)498 void TimePickerRowPattern::MountSecondNode(const RefPtr<FrameNode>& stackSecondNode)
499 {
500     auto host = GetHost();
501     CHECK_NULL_VOID(host);
502     int32_t secondNodePosition = static_cast<int32_t>(host->GetChildren().size()) - 1;
503     if (!HasAmPmNode()) {
504         if (language_ == "ug") {
505             secondNodePosition = CHILD_INDEX_FIRST;
506         }
507     } else {
508         if (amPmTimeOrder_ == "01") {
509             secondNodePosition = CHILD_INDEX_THIRD;
510         } else if (language_ == "ug") {
511             secondNodePosition = CHILD_INDEX_SECOND;
512         }
513     }
514     stackSecondNode->MountToParent(host, secondNodePosition);
515 }
516 
RemoveSecondNode()517 void TimePickerRowPattern::RemoveSecondNode()
518 {
519     auto host = GetHost();
520     CHECK_NULL_VOID(host);
521     int32_t secondNodePosition = static_cast<int32_t>(host->GetChildren().size()) - 1;
522     if (!HasAmPmNode()) {
523         if (language_ == "ug") {
524             secondNodePosition = CHILD_INDEX_FIRST;
525         }
526     } else {
527         if (amPmTimeOrder_ == "01") {
528             secondNodePosition = CHILD_INDEX_THIRD;
529         } else if (language_ == "ug") {
530             secondNodePosition = CHILD_INDEX_SECOND;
531         }
532     }
533     host->RemoveChildAtIndex(secondNodePosition);
534 }
535 
SetAmPmButtonIdeaSize()536 double TimePickerRowPattern::SetAmPmButtonIdeaSize()
537 {
538     auto host = GetHost();
539     CHECK_NULL_RETURN(host, 0);
540     auto children = host->GetChildren();
541     float width = 0.0f;
542     for (const auto& child : children) {
543         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
544         CHECK_NULL_RETURN(buttonNode, 0);
545         width = buttonNode->GetGeometryNode()->GetFrameSize().Width();
546     }
547     if (width > 0) {
548         return width;
549     }
550     return 0;
551 }
552 
SetEventCallback(EventCallback && value)553 void TimePickerRowPattern::SetEventCallback(EventCallback&& value)
554 {
555     auto host = GetHost();
556     CHECK_NULL_VOID(host);
557     auto children = host->GetChildren();
558     for (const auto& child : children) {
559         auto stackNode = DynamicCast<FrameNode>(child);
560         CHECK_NULL_VOID(stackNode);
561         auto columnBlendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
562         CHECK_NULL_VOID(columnBlendNode);
563         auto childNode = DynamicCast<FrameNode>(columnBlendNode->GetLastChild());
564         CHECK_NULL_VOID(childNode);
565         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
566         CHECK_NULL_VOID(timePickerColumnPattern);
567         timePickerColumnPattern->SetEventCallback(std::move(value));
568     }
569 }
570 
FireChangeEvent(bool refresh)571 void TimePickerRowPattern::FireChangeEvent(bool refresh)
572 {
573     if (refresh) {
574         auto timePickerEventHub = GetEventHub<TimePickerEventHub>();
575         CHECK_NULL_VOID(timePickerEventHub);
576         auto str = GetSelectedObject(true);
577         auto info = std::make_shared<DatePickerChangeEvent>(str);
578         timePickerEventHub->FireChangeEvent(info.get());
579         timePickerEventHub->FireDialogChangeEvent(str);
580         firedTimeStr_ = str;
581     }
582 }
583 
SetEnterSelectedAreaEventCallback(EventCallback && value)584 void TimePickerRowPattern::SetEnterSelectedAreaEventCallback(EventCallback&& value)
585 {
586     auto host = GetHost();
587     CHECK_NULL_VOID(host);
588     auto children = host->GetChildren();
589     for (const auto& child : children) {
590         auto stackNode = DynamicCast<FrameNode>(child);
591         CHECK_NULL_VOID(stackNode);
592         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
593         CHECK_NULL_VOID(blendNode);
594         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
595         CHECK_NULL_VOID(childNode);
596         auto pickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
597         CHECK_NULL_VOID(pickerColumnPattern);
598         pickerColumnPattern->SetEnterSelectedAreaEventCallback(std::move(value));
599     }
600 }
601 
FireEnterSelectedAreaEvent(bool refresh)602 void TimePickerRowPattern::FireEnterSelectedAreaEvent(bool refresh)
603 {
604     if (refresh) {
605         auto timePickerEventHub = GetEventHub<TimePickerEventHub>();
606         CHECK_NULL_VOID(timePickerEventHub);
607         auto str = GetEnterObject(true);
608         auto info = std::make_shared<DatePickerChangeEvent>(str);
609         timePickerEventHub->FireEnterSelectedAreaEvent(info.get());
610         timePickerEventHub->FireDialogEnterSelectedAreaEvent(str);
611     }
612 }
613 
GetSelectedObject(bool isColumnChange,int32_t status)614 std::string TimePickerRowPattern::GetSelectedObject(bool isColumnChange, int32_t status)
615 {
616     auto time = selectedTime_;
617     if (isColumnChange) {
618         time = GetCurrentTime();
619     }
620     return time.ToString(true, hasSecond_, status);
621 }
622 
GetCurrentTime()623 PickerTime TimePickerRowPattern::GetCurrentTime()
624 {
625     PickerTime time;
626     UpdateAllChildNode();
627     auto amPmColumn = allChildNode_["amPm"].Upgrade();
628     auto hourColumn = allChildNode_["hour"].Upgrade();
629     auto minuteColumn = allChildNode_["minute"].Upgrade();
630     CHECK_NULL_RETURN(hourColumn, time);
631     CHECK_NULL_RETURN(minuteColumn, time);
632     auto hourPickerColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
633     CHECK_NULL_RETURN(hourPickerColumnPattern, time);
634     auto minutePickerColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
635     CHECK_NULL_RETURN(minutePickerColumnPattern, time);
636     auto hourPickerColumnIndex = hourPickerColumnPattern->GetCurrentIndex();
637     auto hour = GetOptionsValue(hourColumn, hourPickerColumnIndex);
638     auto minutePickerColumnIdex = minutePickerColumnPattern->GetCurrentIndex();
639     auto minute = GetOptionsValue(minuteColumn, minutePickerColumnIdex);
640 
641     if (startTime_.ToMinutes() == START_DEFAULT_TIME.ToMinutes() &&
642         endTime_.ToMinutes() == END_DEFAULT_TIME.ToMinutes()) {
643         if (GetHour24()) {
644             time.SetHour(hourPickerColumnPattern->GetCurrentIndex()); // hour from 0 to 23, index from 0 to 23
645         } else if (amPmColumn) {
646             auto amPmPickerColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
647             CHECK_NULL_RETURN(amPmPickerColumnPattern, time);
648             time.SetHour(GetHourFromAmPm(
649                 amPmPickerColumnPattern->GetCurrentIndex() == 0, hourPickerColumnPattern->GetCurrentIndex() + 1));
650         }
651         time.SetMinute(minutePickerColumnPattern->GetCurrentIndex()); // minute from 0 to 59, index from 0 to 59
652     } else {
653         if (GetHour24()) {
654             time.SetHour(hourPickerColumnPattern->GetCurrentIndex() + startTime_.GetHour());
655         } else if (amPmColumn) {
656             auto amPmPickerColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
657             CHECK_NULL_RETURN(amPmPickerColumnPattern, time);
658             time.SetHour(
659                 GetHourFromAmPm(amPmPickerColumnPattern->GetCurrentIndex() == 0, StringUtils::StringToUint(hour)));
660         }
661         time.SetMinute(StringUtils::StringToUint(minute));
662     }
663 
664     if (hasSecond_) {
665         auto secondColumn = allChildNode_["second"].Upgrade();
666         CHECK_NULL_RETURN(secondColumn, time);
667         auto secondPickerColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
668         CHECK_NULL_RETURN(secondPickerColumnPattern, time);
669         time.SetSecond(secondPickerColumnPattern->GetCurrentIndex()); // second from 0 to 59, index from 0 to 59
670     }
671     return time;
672 }
673 
GetEnterObject(bool isColumnChange,int32_t status)674 std::string TimePickerRowPattern::GetEnterObject(bool isColumnChange, int32_t status)
675 {
676     auto time = selectedTime_;
677     if (isColumnChange) {
678         time = GetCurrentEnterTime();
679     }
680     return time.ToString(true, hasSecond_, status);
681 }
682 
GetCurrentEnterTime()683 PickerTime TimePickerRowPattern::GetCurrentEnterTime()
684 {
685     PickerTime time;
686     UpdateAllChildNode();
687     auto amPmColumn = allChildNode_["amPm"].Upgrade();
688     auto hourColumn = allChildNode_["hour"].Upgrade();
689     auto minuteColumn = allChildNode_["minute"].Upgrade();
690     CHECK_NULL_RETURN(hourColumn, time);
691     CHECK_NULL_RETURN(minuteColumn, time);
692     auto hourPickerColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
693     CHECK_NULL_RETURN(hourPickerColumnPattern, time);
694     auto minutePickerColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
695     CHECK_NULL_RETURN(minutePickerColumnPattern, time);
696 
697     if (GetHour24()) {
698         if (IsStartEndTimeDefined()) {
699             time.SetHour(hourPickerColumnPattern->GetEnterIndex() + startTime_.GetHour());
700         } else {
701             time.SetHour(hourPickerColumnPattern->GetEnterIndex()); // hour from 0 to 23, index from 0 to 23
702         }
703     } else if (amPmColumn) {
704         auto amPmPickerColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
705         CHECK_NULL_RETURN(amPmPickerColumnPattern, time);
706         if (IsStartEndTimeDefined()) {
707             auto hourPickerColumnIndex = hourPickerColumnPattern->GetEnterIndex();
708             auto hour = GetOptionsValue(hourColumn, hourPickerColumnIndex);
709             time.SetHour(
710                 GetHourFromAmPm(amPmPickerColumnPattern->GetEnterIndex() == 0, StringUtils::StringToUint(hour)));
711         } else {
712             time.SetHour(GetHourFromAmPm(
713                 amPmPickerColumnPattern->GetEnterIndex() == 0, hourPickerColumnPattern->GetEnterIndex() + 1));
714         }
715     }
716 
717     time.SetMinute(minutePickerColumnPattern->GetEnterIndex()); // minute from 0 to 59, index from 0 to 59
718     if (hasSecond_) {
719         auto secondColumn = allChildNode_["second"].Upgrade();
720         CHECK_NULL_RETURN(secondColumn, time);
721         auto secondPickerColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
722         CHECK_NULL_RETURN(secondPickerColumnPattern, time);
723         time.SetSecond(secondPickerColumnPattern->GetEnterIndex()); // second from 0 to 59, index from 0 to 59
724     }
725     return time;
726 }
727 
GetHourFromAmPm(bool isAm,uint32_t amPmhour) const728 uint32_t TimePickerRowPattern::GetHourFromAmPm(bool isAm, uint32_t amPmhour) const
729 {
730     if (isAm) {
731         if (amPmhour == AM_PM_HOUR_12) { // AM 12:00 means 00:00
732             return 0;
733         }
734         return amPmhour;
735     }
736     if (amPmhour == AM_PM_HOUR_12) { // PM 12 means 12:00
737         return AM_PM_HOUR_12;
738     }
739     return amPmhour + AM_PM_HOUR_12; // need add 12 hour to 24 hours style
740 }
741 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)742 void TimePickerRowPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, bool needNotify)
743 {
744     std::vector<RefPtr<FrameNode>> tags;
745     if (wheelModeEnabled_ && isEnableCascade_ && !IsStartEndTimeDefined()) {
746         OnDataLinking(tag, isAdd, index, tags);
747     }
748     for (const auto& tag : tags) {
749         auto iter = std::find_if(timePickerColumns_.begin(), timePickerColumns_.end(), [&tag](const auto& c) {
750                 auto column = c.Upgrade();
751                 return column && column->GetId() == tag->GetId();
752             });
753         if (iter != timePickerColumns_.end()) {
754             auto timePickerColumn = (*iter).Upgrade();
755             CHECK_NULL_VOID(timePickerColumn);
756             auto timePickerColumnPattern = timePickerColumn->GetPattern<TimePickerColumnPattern>();
757             CHECK_NULL_VOID(timePickerColumnPattern);
758             timePickerColumnPattern->FlushCurrentOptions();
759         }
760     }
761 
762     HandleColumnsChangeTimeRange(tag);
763 }
764 
IsStartEndTimeDefined()765 bool TimePickerRowPattern::IsStartEndTimeDefined()
766 {
767     auto isStartEndTimeDefined = startTime_.ToMinutes() != START_DEFAULT_TIME.ToMinutes() ||
768                                  endTime_.ToMinutes() != END_DEFAULT_TIME.ToMinutes();
769     return isStartEndTimeDefined;
770 }
771 
HandleColumnsChangeTimeRange(const RefPtr<FrameNode> & tag)772 void TimePickerRowPattern::HandleColumnsChangeTimeRange(const RefPtr<FrameNode>& tag)
773 {
774     if (IsStartEndTimeDefined()) {
775         auto hourColumn = allChildNode_["hour"].Upgrade();
776         CHECK_NULL_VOID(hourColumn);
777         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
778         CHECK_NULL_VOID(hourColumnPattern);
779 
780         auto minuteColumn = allChildNode_["minute"].Upgrade();
781         CHECK_NULL_VOID(minuteColumn);
782         auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
783         CHECK_NULL_VOID(minuteColumnPattern);
784         auto amPmColumn = allChildNode_["amPm"].Upgrade();
785         auto secondColumn = allChildNode_["second"].Upgrade();
786         if (!GetHour24() && tag == amPmColumn) {
787             options_[hourColumn].clear();
788             options_[minuteColumn].clear();
789             UpdateHourAndMinuteTimeRange(tag);
790             UpdateSecondTimeRange();
791             hourColumnPattern->FlushCurrentOptions();
792             minuteColumnPattern->FlushCurrentOptions();
793             auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
794             CHECK_NULL_VOID(amPmColumnPattern);
795             amPmColumnPattern->FlushCurrentOptions();
796             if (hasSecond_ && secondColumn) {
797                 HandleSecondsChangeTimeRange(secondColumn);
798             }
799         } else if (tag == hourColumn || tag == minuteColumn) {
800             options_[hourColumn].clear();
801             options_[minuteColumn].clear();
802             UpdateHourAndMinuteTimeRange(tag);
803             hourColumnPattern->FlushCurrentOptions();
804             minuteColumnPattern->FlushCurrentOptions();
805             if (hasSecond_ && secondColumn) {
806                 HandleSecondsChangeTimeRange(secondColumn);
807             }
808         } else if (tag == secondColumn) {
809             HandleSecondsChangeTimeRange(secondColumn);
810         }
811         oldHourValue_ = GetOptionsCurrentValue(hourColumn);
812         oldMinuteValue_ = GetOptionsCurrentValue(minuteColumn);
813     }
814 }
815 
HandleSecondsChangeTimeRange(const RefPtr<FrameNode> & secondColumn)816 void TimePickerRowPattern::HandleSecondsChangeTimeRange(const RefPtr<FrameNode>& secondColumn)
817 {
818     if (hasSecond_ && secondColumn) {
819         options_[secondColumn].clear();
820         UpdateSecondTimeRange();
821         auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
822         CHECK_NULL_VOID(secondColumnPattern);
823         secondColumnPattern->SetOptions(GetOptionsCount());
824         secondColumnPattern->SetShowCount(GetShowCount());
825         secondColumnPattern->FlushCurrentOptions();
826         secondColumn->MarkModifyDone();
827         secondColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
828     }
829 }
830 
UpdateHourAndMinuteTimeRange(const RefPtr<FrameNode> & tag)831 void TimePickerRowPattern::UpdateHourAndMinuteTimeRange(const RefPtr<FrameNode>& tag)
832 {
833     auto hourColumn = allChildNode_["hour"].Upgrade();
834     CHECK_NULL_VOID(hourColumn);
835     auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
836     CHECK_NULL_VOID(hourColumnPattern);
837     auto minuteColumn = allChildNode_["minute"].Upgrade();
838     CHECK_NULL_VOID(minuteColumn);
839     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
840     CHECK_NULL_VOID(minuteColumnPattern);
841     auto amPmColumn = allChildNode_["amPm"].Upgrade();
842 
843     // update hour column's options
844     HourChangeBuildTimeRange();
845     if (!GetHour24() && tag == amPmColumn) {
846         // update Hour column option after changing ampm column
847         // and set corresponding new index based on old value
848         uint32_t newIndex = INDEX_HOUR_STRAT;
849         if (!GetOptionsIndex(hourColumn, oldHourValue_, newIndex)) {
850             auto uintOldHour = StringUtils::StringToUint(oldHourValue_);
851             if (((IsAmJudgeByAmPmColumn(amPmColumn) && uintOldHour == AM_PM_HOUR_12) ? INDEX_HOUR_STRAT : uintOldHour) <
852                 startTime_.GetHour()) {
853                 newIndex = INDEX_HOUR_STRAT;
854             } else {
855                 newIndex = options_[hourColumn].size() - 1;
856             }
857         }
858         hourColumnPattern->SetCurrentIndex(newIndex);
859         hourColumnPattern->SetEnterIndex(newIndex);
860     }
861     oldHourValue_ = GetOptionsCurrentValue(hourColumn);
862 
863     // update minute column's options
864     auto currentHourOf24 = StringUtils::StringToUint(oldHourValue_);
865     if (!GetHour24()) {
866         currentHourOf24 = GetHourFromAmPm(IsAmJudgeByAmPmColumn(amPmColumn), StringUtils::StringToUint(oldHourValue_));
867     }
868     MinuteChangeBuildTimeRange(currentHourOf24);
869     if (tag != minuteColumn) {
870         uint32_t newIndex = INDEX_MINUTE_STRAT;
871         if (!GetOptionsIndex(minuteColumn, oldMinuteValue_, newIndex)) {
872             if (StringUtils::StringToUint(oldMinuteValue_) < startTime_.GetMinute()) {
873                 newIndex = INDEX_MINUTE_STRAT;
874             } else {
875                 newIndex = options_[minuteColumn].size() - 1;
876             }
877         }
878         minuteColumnPattern->SetCurrentIndex(newIndex);
879         minuteColumnPattern->SetEnterIndex(newIndex);
880     }
881     oldMinuteValue_ = GetOptionsCurrentValue(minuteColumn);
882 }
883 
IsAmJudgeByAmPmColumn(const RefPtr<FrameNode> & amPmColumn)884 bool TimePickerRowPattern::IsAmJudgeByAmPmColumn(const RefPtr<FrameNode>& amPmColumn)
885 {
886     auto isAm = false;
887     CHECK_NULL_RETURN(amPmColumn, isAm);
888     auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
889     CHECK_NULL_RETURN(amPmColumnPattern, false);
890     isAm = (options_[amPmColumn].size() == SIZE_OF_AMPM_COLUMN_OPTION && amPmColumnPattern->GetCurrentIndex() == 0) ||
891            (options_[amPmColumn].size() < SIZE_OF_AMPM_COLUMN_OPTION && IsAmHour(startTime_.GetHour()));
892     return isAm;
893 }
894 
UpdateSecondTimeRange()895 void TimePickerRowPattern::UpdateSecondTimeRange()
896 {
897     auto secondColumn = allChildNode_["second"].Upgrade();
898     CHECK_NULL_VOID(secondColumn);
899     auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
900     CHECK_NULL_VOID(secondColumnPattern);
901     optionsTotalCount_[secondColumn] = 0;
902 
903     for (uint32_t second = INDEX_SECOND_STRAT; second <= INDEX_SECOND_END; second++) { // time's second from 0 to 59
904         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
905             GetPrefixSecond() == ZeroPrefixType::HIDE) {
906             options_[secondColumn][second] = std::to_string(second);
907         } else {
908             if (second < INDEX_SECOND_ADD_ZERO) { // time's second less than 10
909                 options_[secondColumn][second] = std::string("0") + std::to_string(second);
910             } else {
911                 options_[secondColumn][second] = std::to_string(second);
912             }
913         }
914         optionsTotalCount_[secondColumn]++;
915     }
916     secondColumnPattern->SetOptions(GetOptionsCount());
917     IsStartEndTimeDefined() ? secondColumnPattern->SetWheelModeEnabled(false)
918                             : secondColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
919 }
920 
HourChangeBuildTimeRange()921 void TimePickerRowPattern::HourChangeBuildTimeRange()
922 {
923     if (GetHour24()) {
924         Hour24ChangeBuildTimeRange();
925     } else {
926         Hour12ChangeBuildTimeRange();
927     }
928 }
929 
Hour24ChangeBuildTimeRange()930 void TimePickerRowPattern::Hour24ChangeBuildTimeRange()
931 {
932     auto hourColumn = allChildNode_["hour"].Upgrade();
933     CHECK_NULL_VOID(hourColumn);
934     optionsTotalCount_[hourColumn] = 0;
935     auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
936     CHECK_NULL_VOID(hourColumnPattern);
937     for (uint32_t index = 0; index < defined24Hours_.size(); index++) {
938         options_[hourColumn][index] = defined24Hours_[index];
939         optionsTotalCount_[hourColumn]++;
940     }
941     hourColumnPattern->SetOptions(GetOptionsCount());
942     IsStartEndTimeDefined() ? hourColumnPattern->SetWheelModeEnabled(false)
943                             : hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
944     hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
945 }
946 
Hour12ChangeBuildTimeRange()947 void TimePickerRowPattern::Hour12ChangeBuildTimeRange()
948 {
949     auto amPmColumn = allChildNode_["amPm"].Upgrade();
950     CHECK_NULL_VOID(amPmColumn);
951     auto hourColumn = allChildNode_["hour"].Upgrade();
952     CHECK_NULL_VOID(hourColumn);
953     optionsTotalCount_[hourColumn] = 0;
954     auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
955     CHECK_NULL_VOID(hourColumnPattern);
956 
957     if (IsAmJudgeByAmPmColumn(amPmColumn)) {
958         for (uint32_t index = 0; index < definedAMHours_.size(); index++) {
959             options_[hourColumn][index] = definedAMHours_[index];
960             optionsTotalCount_[hourColumn]++;
961         }
962     } else {
963         for (uint32_t index = 0; index < definedPMHours_.size(); index++) {
964             options_[hourColumn][index] = definedPMHours_[index];
965             optionsTotalCount_[hourColumn]++;
966         }
967     }
968 
969     hourColumnPattern->SetOptions(GetOptionsCount());
970     IsStartEndTimeDefined() ? hourColumnPattern->SetWheelModeEnabled(false)
971                             : hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
972 }
973 
MinuteChangeBuildTimeRange(uint32_t hourOf24)974 void TimePickerRowPattern::MinuteChangeBuildTimeRange(uint32_t hourOf24)
975 {
976     uint32_t startMinute = (hourOf24 == startTime_.GetHour()) ? startTime_.GetMinute() : INDEX_MINUTE_STRAT;
977     uint32_t endMinute = (hourOf24 == endTime_.GetHour()) ? endTime_.GetMinute() : INDEX_MINUTE_END;
978     auto minuteColumn = allChildNode_["minute"].Upgrade();
979     CHECK_NULL_VOID(minuteColumn);
980     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
981     CHECK_NULL_VOID(minuteColumnPattern);
982     optionsTotalCount_[minuteColumn] = 0;
983     uint32_t index = 0;
984     for (uint32_t minute = startMinute; minute <= endMinute; minute++) {
985         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
986             GetPrefixMinute() == ZeroPrefixType::HIDE) {
987             options_[minuteColumn][index] = std::to_string(minute);
988         } else {
989             options_[minuteColumn][index] =
990                 (minute < MINUTE_10) ? std::string("0") + std::to_string(minute) : std::to_string(minute);
991         }
992         optionsTotalCount_[minuteColumn]++;
993         index++;
994     }
995 
996     minuteColumnPattern->SetOptions(GetOptionsCount());
997     IsStartEndTimeDefined() ? minuteColumnPattern->SetWheelModeEnabled(false)
998                             : minuteColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
999 }
1000 
OnFontConfigurationUpdate()1001 void TimePickerRowPattern::OnFontConfigurationUpdate()
1002 {
1003     CHECK_NULL_VOID(closeDialogEvent_);
1004     closeDialogEvent_();
1005 }
1006 
OnFontScaleConfigurationUpdate()1007 void TimePickerRowPattern::OnFontScaleConfigurationUpdate()
1008 {
1009     CHECK_NULL_VOID(closeDialogEvent_);
1010     closeDialogEvent_();
1011 }
1012 
UpdateConfirmButtonMargin(const RefPtr<FrameNode> & buttonConfirmNode,const RefPtr<DialogTheme> & dialogTheme)1013 void TimePickerRowPattern::UpdateConfirmButtonMargin(
1014     const RefPtr<FrameNode>& buttonConfirmNode, const RefPtr<DialogTheme>& dialogTheme)
1015 {
1016     MarginProperty margin;
1017     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
1018     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1019         DialogTypeMargin::UpdateDialogMargin(isRtl, margin, dialogTheme, true, ModuleDialogType::TIMEPICKER_DIALOG);
1020     } else {
1021         DialogTypeMargin::UpdateDialogMargin(isRtl, margin, dialogTheme, false, ModuleDialogType::TIMEPICKER_DIALOG);
1022     }
1023     buttonConfirmNode->GetLayoutProperty()->UpdateMargin(margin);
1024 }
1025 
UpdateCancelButtonMargin(const RefPtr<FrameNode> & buttonCancelNode,const RefPtr<DialogTheme> & dialogTheme)1026 void TimePickerRowPattern::UpdateCancelButtonMargin(
1027     const RefPtr<FrameNode>& buttonCancelNode, const RefPtr<DialogTheme>& dialogTheme)
1028 {
1029     MarginProperty margin;
1030     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
1031     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1032         DialogTypeMargin::UpdateDialogMargin(!isRtl, margin, dialogTheme, true, ModuleDialogType::TIMEPICKER_DIALOG);
1033     } else {
1034         DialogTypeMargin::UpdateDialogMargin(!isRtl, margin, dialogTheme, false,
1035             ModuleDialogType::TIMEPICKER_DIALOG);
1036     }
1037     buttonCancelNode->GetLayoutProperty()->UpdateMargin(margin);
1038 }
1039 
OnLanguageConfigurationUpdate()1040 void TimePickerRowPattern::OnLanguageConfigurationUpdate()
1041 {
1042     FlushAmPmFormatString();
1043     UpdateLanguageAndAmPmTimeOrder();
1044     if (!GetHour24()) {
1045         auto host = GetHost();
1046         CHECK_NULL_VOID(host);
1047         auto children = host->GetChildren();
1048         auto iter = children.begin();
1049         CHECK_NULL_VOID(*iter);
1050         auto amPmNode = *iter;
1051         CHECK_NULL_VOID(amPmNode);
1052         if (amPmTimeOrder_ == "01" && isAmPmTimeOrderUpdate_) {
1053             // if hasSecond_ is true, then amPmNode should be moved from slot 0 to 3, otherwise from slot 0 to 2
1054             hasSecond_ ? amPmNode->MovePosition(3) : amPmNode->MovePosition(2);
1055         } else if (amPmTimeOrder_ == "10" && isAmPmTimeOrderUpdate_) {
1056             // if hasSecond_ is true, then amPmNode should be moved from slot 3 to 0, otherwise form slot 2 to 0
1057             hasSecond_ ? std::advance(iter, 3) : std::advance(iter, 2);
1058             amPmNode = *iter;
1059             CHECK_NULL_VOID(amPmNode);
1060             amPmNode->MovePosition(0);
1061         }
1062         UpdateNodePositionForUg();
1063         auto layoutProperty = AceType::DynamicCast<FrameNode>(amPmNode)->GetLayoutProperty<LayoutProperty>();
1064         layoutProperty->UpdateAlignment(Alignment::CENTER);
1065         layoutProperty->UpdateLayoutWeight(1);
1066         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1067     }
1068     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
1069     CHECK_NULL_VOID(buttonConfirmNode);
1070     auto confirmNode = AceType::DynamicCast<FrameNode>(buttonConfirmNode->GetFirstChild());
1071     CHECK_NULL_VOID(confirmNode);
1072     auto confirmNodeLayout = confirmNode->GetLayoutProperty<TextLayoutProperty>();
1073     CHECK_NULL_VOID(confirmNodeLayout);
1074     confirmNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.ok"));
1075     auto pipeline = confirmNode->GetContextRefPtr();
1076     CHECK_NULL_VOID(pipeline);
1077     auto dialogTheme = pipeline->GetTheme<DialogTheme>();
1078     CHECK_NULL_VOID(dialogTheme);
1079     UpdateConfirmButtonMargin(buttonConfirmNode, dialogTheme);
1080     confirmNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1081 
1082     auto buttonCancelNode = weakButtonCancel_.Upgrade();
1083     CHECK_NULL_VOID(buttonCancelNode);
1084     auto cancelNode = AceType::DynamicCast<FrameNode>(buttonCancelNode->GetFirstChild());
1085     CHECK_NULL_VOID(cancelNode);
1086     auto cancelNodeLayout = cancelNode->GetLayoutProperty<TextLayoutProperty>();
1087     CHECK_NULL_VOID(cancelNodeLayout);
1088     cancelNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.cancel"));
1089     UpdateCancelButtonMargin(buttonCancelNode, dialogTheme);
1090     cancelNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1091 }
1092 
UpdateNodePositionForUg()1093 void TimePickerRowPattern::UpdateNodePositionForUg()
1094 {
1095     if (!isPreLanguageUg_ && language_ != "ug") {
1096         return;
1097     }
1098 
1099     auto host = GetHost();
1100     CHECK_NULL_VOID(host);
1101     // ug's node order is S:M:H, need to change it to H:M:S
1102     if (isPreLanguageUg_ && isAmPmTimeOrderUpdate_) {
1103         if (hasSecond_) {
1104             auto secondNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
1105             CHECK_NULL_VOID(secondNode);
1106             secondNode->MovePosition(CHILD_INDEX_THIRD);
1107 
1108             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
1109             CHECK_NULL_VOID(minuteNode);
1110             minuteNode->MovePosition(CHILD_INDEX_SECOND);
1111         } else {
1112             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FIRST);
1113             CHECK_NULL_VOID(minuteNode);
1114             minuteNode->MovePosition(CHILD_INDEX_SECOND);
1115         }
1116     } else if ((isPreLanguageUg_ && !isAmPmTimeOrderUpdate_) || (language_ == "ug")) {
1117         if (hasSecond_) {
1118             auto hourNode = host->GetChildAtIndex(CHILD_INDEX_FOURTH);
1119             CHECK_NULL_VOID(hourNode);
1120             hourNode->MovePosition(CHILD_INDEX_SECOND);
1121             auto minuteNode = host->GetChildAtIndex(CHILD_INDEX_FOURTH);
1122             CHECK_NULL_VOID(minuteNode);
1123             minuteNode->MovePosition(CHILD_INDEX_THIRD);
1124         } else {
1125             auto hourNode = host->GetChildAtIndex(CHILD_INDEX_THIRD);
1126             CHECK_NULL_VOID(hourNode);
1127             hourNode->MovePosition(CHILD_INDEX_SECOND);
1128         }
1129     }
1130     if (isPreLanguageUg_) {
1131         isPreLanguageUg_ = false;
1132     }
1133 }
1134 
FlushAmPmFormatString()1135 void TimePickerRowPattern::FlushAmPmFormatString()
1136 {
1137     auto amPmStrings = Localization::GetInstance()->GetAmPmStrings();
1138     if (amPmStrings.size() > 1) {
1139         vecAmPm_.clear();
1140         std::string am = amPmStrings[0];
1141         vecAmPm_.emplace_back(am);
1142         std::string pm = amPmStrings[1];
1143         vecAmPm_.emplace_back(pm);
1144     }
1145 }
1146 
SetChangeCallback(ColumnChangeCallback && value)1147 void TimePickerRowPattern::SetChangeCallback(ColumnChangeCallback&& value)
1148 {
1149     auto host = GetHost();
1150     CHECK_NULL_VOID(host);
1151     auto children = host->GetChildren();
1152     for (const auto& child : children) {
1153         auto stackNode = DynamicCast<FrameNode>(child);
1154         CHECK_NULL_VOID(stackNode);
1155         auto columnBlendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1156         CHECK_NULL_VOID(columnBlendNode);
1157         auto childNode = DynamicCast<FrameNode>(columnBlendNode->GetLastChild());
1158         CHECK_NULL_VOID(childNode);
1159         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
1160         CHECK_NULL_VOID(timePickerColumnPattern);
1161         timePickerColumnPattern->SetChangeCallback(std::move(value));
1162     }
1163 }
1164 
FlushColumn()1165 void TimePickerRowPattern::FlushColumn()
1166 {
1167     UpdateAllChildNode();
1168     auto amPmColumn = allChildNode_["amPm"].Upgrade();
1169     auto hourColumn = allChildNode_["hour"].Upgrade();
1170     if (GetHour24()) {
1171         CHECK_NULL_VOID(hourColumn);
1172         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1173         CHECK_NULL_VOID(hourColumnPattern);
1174         hourColumnPattern->SetOptions(GetOptionsCount());
1175         hourColumnPattern->SetShowCount(GetShowCount());
1176         hourColumnPattern->FlushCurrentOptions();
1177         hourColumn->MarkModifyDone();
1178         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1179     } else if (amPmColumn) {
1180         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
1181         CHECK_NULL_VOID(amPmColumnPattern);
1182         amPmColumnPattern->SetShowCount(AM_PM_COUNT);
1183         amPmColumnPattern->FlushCurrentOptions();
1184         amPmColumn->MarkModifyDone();
1185         amPmColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1186 
1187         CHECK_NULL_VOID(hourColumn);
1188         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1189         CHECK_NULL_VOID(hourColumnPattern);
1190         hourColumnPattern->SetOptions(GetOptionsCount());
1191         hourColumnPattern->SetShowCount(GetShowCount());
1192         hourColumnPattern->FlushCurrentOptions();
1193         hourColumn->MarkModifyDone();
1194         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1195     }
1196 
1197     auto minuteColumn = allChildNode_["minute"].Upgrade();
1198     CHECK_NULL_VOID(minuteColumn);
1199     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
1200     CHECK_NULL_VOID(minuteColumnPattern);
1201     minuteColumnPattern->SetShowCount(GetShowCount());
1202     minuteColumnPattern->FlushCurrentOptions();
1203     minuteColumn->MarkModifyDone();
1204     minuteColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1205     if (hasSecond_) {
1206         auto secondColumn = allChildNode_["second"].Upgrade();
1207         CHECK_NULL_VOID(secondColumn);
1208         auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
1209         CHECK_NULL_VOID(secondColumnPattern);
1210         secondColumnPattern->SetOptions(GetOptionsCount());
1211         secondColumnPattern->SetShowCount(GetShowCount());
1212         secondColumnPattern->FlushCurrentOptions();
1213     }
1214 }
1215 
OnDataLinking(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1216 void TimePickerRowPattern::OnDataLinking(
1217     const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1218 {
1219     CHECK_NULL_VOID(tag);
1220     auto hourNode = allChildNode_["hour"].Upgrade();
1221     CHECK_NULL_VOID(hourNode);
1222     if (tag->GetId() != hourNode->GetId()) {
1223         return;
1224     }
1225 
1226     if (!GetHour24()) {
1227         HandleHour12Change(isAdd, index, resultTags);
1228     }
1229 }
1230 
GetOptionsValue(const RefPtr<FrameNode> & frameNode,uint32_t optionIndex)1231 const std::string& TimePickerRowPattern::GetOptionsValue(const RefPtr<FrameNode>& frameNode, uint32_t optionIndex)
1232 {
1233     UpdateAllChildNode();
1234     if (frameNode == allChildNode_["amPm"]) {
1235         return options_[allChildNode_["amPm"]][optionIndex];
1236     }
1237     bool isHour12 = !GetHour24();
1238     auto isHourNode = frameNode == allChildNode_["hour"];
1239     if (options_.find(frameNode) == options_.end()) {
1240         options_[frameNode] = std::unordered_map<uint32_t, std::string>();
1241     }
1242     if (options_[frameNode].find(optionIndex) == options_[frameNode].end()) {
1243         options_[frameNode][optionIndex] =
1244             isHourNode ? GetHourFormatString(optionIndex + isHour12) : GetMinuteFormatString(optionIndex);
1245     }
1246     return options_[frameNode][optionIndex];
1247 }
1248 
GetOptionsIndex(const RefPtr<FrameNode> & frameNode,const std::string & value,uint32_t & columnIndex)1249 bool TimePickerRowPattern::GetOptionsIndex(
1250     const RefPtr<FrameNode>& frameNode, const std::string& value, uint32_t& columnIndex)
1251 {
1252     CHECK_NULL_RETURN(frameNode, false);
1253     bool result = false;
1254     auto columnFound = options_.find(frameNode);
1255     if (columnFound != options_.end()) {
1256         for (const auto& option : columnFound->second) {
1257             if (option.second == value) {
1258                 columnIndex = option.first;
1259                 result = true;
1260             }
1261         }
1262     }
1263     return result;
1264 }
1265 
GetOptionsCurrentValue(const RefPtr<FrameNode> & frameNode)1266 std::string TimePickerRowPattern::GetOptionsCurrentValue(const RefPtr<FrameNode>& frameNode)
1267 {
1268     std::string result = "";
1269     CHECK_NULL_RETURN(frameNode, result);
1270     auto columnFound = options_.find(frameNode);
1271     if (columnFound != options_.end()) {
1272         auto columnPattern = frameNode->GetPattern<TimePickerColumnPattern>();
1273         CHECK_NULL_RETURN(columnPattern, result);
1274         auto currentIndex = columnPattern->GetCurrentIndex();
1275         for (const auto& option : columnFound->second) {
1276             if (option.first == currentIndex) {
1277                 result = option.second;
1278             }
1279         }
1280     }
1281     return result;
1282 }
1283 
GetOptionsValueWithIndex(const RefPtr<FrameNode> & frameNode,uint32_t optionIndex)1284 std::string TimePickerRowPattern::GetOptionsValueWithIndex(const RefPtr<FrameNode>& frameNode, uint32_t optionIndex)
1285 {
1286     std::string result = "";
1287     CHECK_NULL_RETURN(frameNode, result);
1288     auto columnFound = options_.find(frameNode);
1289     if (columnFound != options_.end()) {
1290         auto currentIndex = optionIndex;
1291         for (const auto& option : columnFound->second) {
1292             if (option.first == currentIndex) {
1293                 result = option.second;
1294             }
1295         }
1296     }
1297     return result;
1298 }
1299 
OnColumnsBuilding()1300 void TimePickerRowPattern::OnColumnsBuilding()
1301 {
1302     if (IsStartEndTimeDefined()) {
1303         HandleHourColumnBuildingRange(GetSelectedTime());
1304         HandleMinAndSecColumnBuildingRange();
1305         RecordHourAndMinuteOptions();
1306     } else {
1307         HandleHourColumnBuilding();
1308         HandleMinAndSecColumnBuilding();
1309     }
1310 }
1311 
HandleHourColumnBuilding()1312 void TimePickerRowPattern::HandleHourColumnBuilding()
1313 {
1314     UpdateAllChildNode();
1315     auto hourColumn = allChildNode_["hour"].Upgrade();
1316     CHECK_NULL_VOID(hourColumn);
1317     optionsTotalCount_[hourColumn] = 0;
1318     if (GetHour24()) {
1319         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1320         CHECK_NULL_VOID(hourColumnPattern);
1321         for (uint32_t hour = 0; hour <= 23; ++hour) { // time's hour from 0 to 23.
1322             if (hour == selectedTime_.GetHour()) {
1323                 hourColumnPattern->SetCurrentIndex(hour);
1324                 hourColumnPattern->SetEnterIndex(hour);
1325             }
1326             optionsTotalCount_[hourColumn]++;
1327         }
1328         hourColumnPattern->SetOptions(GetOptionsCount());
1329         hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1330         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1331     } else {
1332         auto amPmColumn = allChildNode_["amPm"].Upgrade();
1333         CHECK_NULL_VOID(amPmColumn);
1334         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
1335         CHECK_NULL_VOID(amPmColumnPattern);
1336         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1337         CHECK_NULL_VOID(hourColumnPattern);
1338         options_[amPmColumn][INDEX_AM_0] = GetAmFormatString();
1339         options_[amPmColumn][INDEX_PM_1] = GetPmFormatString();
1340 
1341         if (IsAmHour(selectedTime_.GetHour())) {
1342             amPmColumnPattern->SetCurrentIndex(0); // AM's index
1343             amPmColumnPattern->SetEnterIndex(0);
1344         } else {
1345             amPmColumnPattern->SetCurrentIndex(1); // PM's index
1346             amPmColumnPattern->SetEnterIndex(1);
1347         }
1348         optionsTotalCount_[amPmColumn] = CHILD_WITHOUT_AMPM_SIZE;
1349         auto selectedHour = GetAmPmHour(selectedTime_.GetHour());
1350         for (uint32_t hour = 1; hour <= AM_PM_HOUR_12; ++hour) { // AM_PM hour start from 1 to 12
1351             if (hour == selectedHour) {
1352                 hourColumnPattern->SetCurrentIndex(hour - 1);
1353                 hourColumnPattern->SetEnterIndex(hour - 1);
1354             }
1355             optionsTotalCount_[hourColumn]++;
1356         }
1357         amPmColumnPattern->SetOptions(GetOptionsCount());
1358         hourColumnPattern->SetOptions(GetOptionsCount());
1359         amPmColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1360         hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1361     }
1362 }
1363 
HandleMinAndSecColumnBuilding()1364 void TimePickerRowPattern::HandleMinAndSecColumnBuilding()
1365 {
1366     UpdateAllChildNode();
1367     auto minuteColumn = allChildNode_["minute"].Upgrade();
1368     CHECK_NULL_VOID(minuteColumn);
1369     MinOrSecColumnBuilding(minuteColumn, GetPrefixMinute() == ZeroPrefixType::HIDE, selectedTime_.GetMinute());
1370     auto secondColumn = allChildNode_["second"].Upgrade();
1371     CHECK_NULL_VOID(secondColumn);
1372     MinOrSecColumnBuilding(secondColumn, GetPrefixSecond() == ZeroPrefixType::HIDE, selectedTime_.GetSecond());
1373 }
1374 
MinOrSecColumnBuilding(const RefPtr<FrameNode> & columnFrameNode,bool isZeroPrefixTypeHide,uint32_t selectedTime)1375 void TimePickerRowPattern::MinOrSecColumnBuilding(
1376     const RefPtr<FrameNode>& columnFrameNode, bool isZeroPrefixTypeHide, uint32_t selectedTime)
1377 {
1378     CHECK_NULL_VOID(columnFrameNode);
1379     auto columnPattern = columnFrameNode->GetPattern<TimePickerColumnPattern>();
1380     CHECK_NULL_VOID(columnPattern);
1381     optionsTotalCount_[columnFrameNode] = 0;
1382 
1383     for (uint32_t time = 0; time <= 59; ++time) { // time's minute or second from 0 to 59
1384         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) && isZeroPrefixTypeHide) {
1385             options_[columnFrameNode][time] = std::to_string(time);
1386         } else {
1387             if (time < 10) { // time's minute or second less than 10
1388                 options_[columnFrameNode][time] = std::string("0") + std::to_string(time);
1389             }
1390         }
1391         if (time == selectedTime) {
1392             columnPattern->SetCurrentIndex(time);
1393             columnPattern->SetEnterIndex(time);
1394         }
1395         optionsTotalCount_[columnFrameNode]++;
1396     }
1397     columnPattern->SetOptions(GetOptionsCount());
1398     columnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1399 }
1400 
RecordHourAndMinuteOptions()1401 void TimePickerRowPattern::RecordHourAndMinuteOptions()
1402 {
1403     RecordHourOptions();
1404     RecordHourMinuteValues();
1405 }
1406 
RecordHourOptions()1407 void TimePickerRowPattern::RecordHourOptions()
1408 {
1409     uint32_t startHour = startTime_.GetHour();
1410     uint32_t endHour = endTime_.GetHour();
1411     definedAMHours_.clear();
1412     definedAMHours_.shrink_to_fit();
1413     definedPMHours_.clear();
1414     definedPMHours_.shrink_to_fit();
1415     defined24Hours_.clear();
1416     defined24Hours_.shrink_to_fit();
1417     if (GetHour24()) {
1418         for (uint32_t hour = startHour; hour <= endHour; ++hour) {
1419             defined24Hours_.emplace_back(GetHourFormatString(hour));
1420         }
1421     } else {
1422         bool isAmStart = IsAmHour(startHour);
1423         bool isAmEnd = IsAmHour(endHour);
1424         if (isAmStart && !isAmEnd) {
1425             // start time is in the morning and end time is in the afternoon
1426             for (uint32_t hour = startHour; hour <= AM_PM_HOUR_11; hour++) {
1427                 definedAMHours_.emplace_back(GetHourFormatString(GetAmPmHour(hour)));
1428             }
1429             for (uint32_t hour = AM_PM_HOUR_12; hour <= endHour; hour++) {
1430                 definedPMHours_.emplace_back(GetHourFormatString(GetAmPmHour(hour)));
1431             }
1432         } else if (isAmStart) {
1433             // both start time and end time are in the morning
1434             for (uint32_t hour = startHour; hour <= endHour; hour++) {
1435                 definedAMHours_.emplace_back(GetHourFormatString(GetAmPmHour(hour)));
1436             }
1437         } else {
1438             // both start time and end time are in the afternoon
1439             for (uint32_t hour = startHour; hour <= endHour; hour++) {
1440                 definedPMHours_.emplace_back(GetHourFormatString(GetAmPmHour(hour)));
1441             }
1442         }
1443     }
1444 }
1445 
RecordHourMinuteValues()1446 void TimePickerRowPattern::RecordHourMinuteValues()
1447 {
1448     auto hourColumn = allChildNode_["hour"].Upgrade();
1449     CHECK_NULL_VOID(hourColumn);
1450     oldHourValue_ = GetOptionsCurrentValue(hourColumn);
1451 
1452     auto minuteColumn = allChildNode_["minute"].Upgrade();
1453     CHECK_NULL_VOID(minuteColumn);
1454     oldMinuteValue_ = GetOptionsCurrentValue(minuteColumn);
1455 }
1456 
HandleHourColumnBuildingRange(const PickerTime & value)1457 void TimePickerRowPattern::HandleHourColumnBuildingRange(const PickerTime& value)
1458 {
1459     UpdateAllChildNode();
1460     uint32_t startHour = startTime_.GetHour();
1461     uint32_t endHour = endTime_.GetHour();
1462     auto amPmColumn = allChildNode_["amPm"].Upgrade();
1463     auto hourColumn = allChildNode_["hour"].Upgrade();
1464     optionsTotalCount_[hourColumn] = 0;
1465     if (GetHour24()) {
1466         CHECK_NULL_VOID(hourColumn);
1467         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1468         CHECK_NULL_VOID(hourColumnPattern);
1469         for (uint32_t hour = startHour; hour <= endHour; ++hour) {
1470             options_[hourColumn][hour - startHour] = GetHourFormatString(hour);
1471             if (hour == value.GetHour()) {
1472                 hourColumnPattern->SetCurrentIndex(hour - startHour);
1473                 hourColumnPattern->SetEnterIndex(hour - startHour);
1474             }
1475             optionsTotalCount_[hourColumn]++;
1476         }
1477         hourColumnPattern->SetOptions(GetOptionsCount());
1478         IsStartEndTimeDefined() ? hourColumnPattern->SetWheelModeEnabled(false)
1479                                 : hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1480         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1481     } else {
1482         HandleAmPmColumnBuilding(value);
1483     }
1484 }
1485 
HandleAmPmColumnBuilding(const PickerTime & value)1486 void TimePickerRowPattern::HandleAmPmColumnBuilding(const PickerTime& value)
1487 {
1488     UpdateAllChildNode();
1489     auto amPmColumn = allChildNode_["amPm"].Upgrade();
1490     auto hourColumn = allChildNode_["hour"].Upgrade();
1491     CHECK_NULL_VOID(amPmColumn);
1492     CHECK_NULL_VOID(hourColumn);
1493     auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
1494     CHECK_NULL_VOID(amPmColumnPattern);
1495     auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1496     CHECK_NULL_VOID(hourColumnPattern);
1497     options_[amPmColumn][INDEX_AM_0] = GetAmFormatString();
1498     options_[amPmColumn][INDEX_PM_1] = GetPmFormatString();
1499 
1500     if (IsAmHour(value.GetHour())) {
1501         amPmColumnPattern->SetCurrentIndex(0); // AM's index
1502         amPmColumnPattern->SetEnterIndex(0);
1503     } else {
1504         amPmColumnPattern->SetCurrentIndex(1); // PM's index
1505         amPmColumnPattern->SetEnterIndex(1);
1506     }
1507     optionsTotalCount_[amPmColumn] = CHILD_WITHOUT_AMPM_SIZE;
1508     if (startTime_.ToMinutes() == START_DEFAULT_TIME.ToMinutes() &&
1509         endTime_.ToMinutes() == END_DEFAULT_TIME.ToMinutes()) {
1510         auto selectedHour = GetAmPmHour(selectedTime_.GetHour());
1511         for (uint32_t hour = 1; hour <= AM_PM_HOUR_12; ++hour) {
1512             if (hour == selectedHour) {
1513                 hourColumnPattern->SetCurrentIndex(hour - 1);
1514                 hourColumnPattern->SetEnterIndex(hour - 1);
1515             }
1516             optionsTotalCount_[hourColumn]++;
1517         }
1518     } else {
1519         HandleAmPmColumnChange(value.GetHour());
1520     }
1521     amPmColumnPattern->SetOptions(GetOptionsCount());
1522     hourColumnPattern->SetOptions(GetOptionsCount());
1523     amPmColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1524     IsStartEndTimeDefined() ? hourColumnPattern->SetWheelModeEnabled(false)
1525                             : hourColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1526 }
1527 
HandleAmPmColumnChange(uint32_t selectedHour)1528 void TimePickerRowPattern::HandleAmPmColumnChange(uint32_t selectedHour)
1529 {
1530     auto amPmColumn = allChildNode_["amPm"].Upgrade();
1531     auto hourColumn = allChildNode_["hour"].Upgrade();
1532     CHECK_NULL_VOID(amPmColumn);
1533     CHECK_NULL_VOID(hourColumn);
1534     uint32_t startHour = startTime_.GetHour();
1535     uint32_t endHour = endTime_.GetHour();
1536     bool isAmStart = IsAmHour(startHour);
1537     bool isAmEnd = IsAmHour(endHour);
1538     if (isAmStart && !isAmEnd) {
1539         endHour = ParseHourOf24(endHour);
1540         if (IsAmHour(selectedHour)) {
1541             endHour = AM_PM_HOUR_11;
1542         } else {
1543             startHour = 0;
1544         }
1545     } else {
1546         options_[amPmColumn][INDEX_AM_0] = isAmStart ? GetAmFormatString() : GetPmFormatString();
1547         optionsTotalCount_[amPmColumn] = 1;
1548         startHour = ParseHourOf24(startHour);
1549         endHour = ParseHourOf24(endHour);
1550     }
1551     HandleAmToPmHourColumnBuilding(selectedHour, startHour, endHour);
1552 }
1553 
HandleAmToPmHourColumnBuilding(uint32_t selectedHour,uint32_t startHour,uint32_t endHour)1554 void TimePickerRowPattern::HandleAmToPmHourColumnBuilding(uint32_t selectedHour, uint32_t startHour, uint32_t endHour)
1555 {
1556     auto hourColumn = allChildNode_["hour"].Upgrade();
1557     CHECK_NULL_VOID(hourColumn);
1558     auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
1559     CHECK_NULL_VOID(hourColumnPattern);
1560     uint32_t selectedParseHour = ParseHourOf24(selectedHour);
1561     for (uint32_t hour = startHour; hour <= endHour; ++hour) {
1562         if (hour == 0) {
1563             options_[hourColumn][INDEX_HOUR_STRAT] = GetHourFormatString(AM_PM_HOUR_12);
1564         } else {
1565             options_[hourColumn][hour - startHour] = GetHourFormatString(hour);
1566         }
1567         if (hour == selectedParseHour) {
1568             hourColumnPattern->SetCurrentIndex(hour - startHour);
1569             hourColumnPattern->SetEnterIndex(hour - startHour);
1570         }
1571         optionsTotalCount_[hourColumn]++;
1572     }
1573 }
1574 
HandleMinAndSecColumnBuildingRange()1575 void TimePickerRowPattern::HandleMinAndSecColumnBuildingRange()
1576 {
1577     UpdateAllChildNode();
1578     HandleMinColumnChange(selectedTime_);
1579     UpdateSecondTimeRange();
1580     auto secondColumn = allChildNode_["second"].Upgrade();
1581     CHECK_NULL_VOID(secondColumn);
1582     auto secondColumnPattern = secondColumn->GetPattern<TimePickerColumnPattern>();
1583     CHECK_NULL_VOID(secondColumnPattern);
1584     secondColumnPattern->SetCurrentIndex(selectedTime_.GetSecond());
1585     secondColumnPattern->SetEnterIndex(selectedTime_.GetSecond());
1586 }
1587 
HandleMinColumnChange(const PickerTime & value)1588 void TimePickerRowPattern::HandleMinColumnChange(const PickerTime& value)
1589 {
1590     uint32_t startMinue = (startTime_.GetHour() == value.GetHour()) ? startTime_.GetMinute() : 0;
1591     uint32_t endMinute = (endTime_.GetHour() == value.GetHour()) ? endTime_.GetMinute() : 59;
1592     auto minuteColumn = allChildNode_["minute"].Upgrade();
1593     CHECK_NULL_VOID(minuteColumn);
1594     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
1595     CHECK_NULL_VOID(minuteColumnPattern);
1596     optionsTotalCount_[minuteColumn] = 0;
1597 
1598     for (uint32_t minute = startMinue; minute <= endMinute; ++minute) {
1599         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE) &&
1600             GetPrefixMinute() == ZeroPrefixType::HIDE) {
1601             options_[minuteColumn][minute - startMinue] = std::to_string(minute);
1602         } else {
1603             options_[minuteColumn][minute - startMinue] =
1604                 (minute < MINUTE_10) ? std::string("0") + std::to_string(minute) : std::to_string(minute);
1605         }
1606         if (minute == value.GetMinute()) {
1607             minuteColumnPattern->SetCurrentIndex(minute - startMinue);
1608             minuteColumnPattern->SetEnterIndex(minute - startMinue);
1609         }
1610         optionsTotalCount_[minuteColumn]++;
1611     }
1612     minuteColumnPattern->SetOptions(GetOptionsCount());
1613     IsStartEndTimeDefined() ? minuteColumnPattern->SetWheelModeEnabled(false)
1614                             : minuteColumnPattern->SetWheelModeEnabled(wheelModeEnabled_);
1615 }
1616 
SetSelectedTime(const PickerTime & value)1617 void TimePickerRowPattern::SetSelectedTime(const PickerTime& value)
1618 {
1619     selectedTime_ = AdjustTime(value);
1620     isFiredTimeChange_ = firedTimeStr_.has_value() && firedTimeStr_.value() == selectedTime_.ToString(true, hasSecond_);
1621     firedTimeStr_.reset();
1622 }
1623 
1624 
AdjustTime(const PickerTime & time)1625 PickerTime TimePickerRowPattern::AdjustTime(const PickerTime& time)
1626 {
1627     if (time.ToMinutes() < startTime_.ToMinutes()) {
1628         return startTime_;
1629     }
1630     if (time.ToMinutes() > endTime_.ToMinutes()) {
1631         return endTime_;
1632     }
1633     return time;
1634 }
1635 
UpdateAllChildNode()1636 void TimePickerRowPattern::UpdateAllChildNode()
1637 {
1638     if (hasSecond_) {
1639         GetAllChildNodeWithSecond();
1640         return;
1641     }
1642     auto host = GetHost();
1643     CHECK_NULL_VOID(host);
1644     if (GetHour24() && host->GetChildren().size() == CHILD_WITH_AMPM_SIZE) {
1645         // if amPmTimeOrder is "10", amPm node is in slot 0, otherwise in slot 2
1646         host->RemoveChildAtIndex(amPmTimeOrder_ == "10" ? AMPMDEFAULTPOSITION : AMPM_FORWARD_WITHOUTSECOND);
1647         amPmId_.reset();
1648         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1649         host->MarkModifyDone();
1650     } else if (!GetHour24() && host->GetChildren().size() == CHILD_WITHOUT_AMPM_SIZE) {
1651         CreateAmPmNode();
1652     }
1653     if (GetHour24() && host->GetChildren().size() != CHILD_WITHOUT_AMPM_SIZE) {
1654         return;
1655     }
1656 
1657     if (!GetHour24() && host->GetChildren().size() != CHILD_WITH_AMPM_SIZE) {
1658         return;
1659     }
1660     if (language_ == "ug") {
1661         UpdateAllChildNodeForUg();
1662         return;
1663     }
1664     auto children = host->GetChildren();
1665     auto iter = children.begin();
1666     CHECK_NULL_VOID(*iter);
1667     auto amPmNode = GetAmPmNode(iter);
1668     auto hourNode = GetHourNode(iter);
1669     auto minuteNode = GetMinuteNode(iter);
1670     allChildNode_["amPm"] = amPmNode;
1671     allChildNode_["hour"] = hourNode;
1672     allChildNode_["minute"] = minuteNode;
1673 }
1674 
GetAllChildNodeWithSecond()1675 void TimePickerRowPattern::GetAllChildNodeWithSecond()
1676 {
1677     auto host = GetHost();
1678     CHECK_NULL_VOID(host);
1679     if (GetHour24() && host->GetChildren().size() == CHILD_WITH_AMPM_SIZE + 1) {
1680         host->RemoveChildAtIndex(amPmTimeOrder_ == "10" ? AMPMDEFAULTPOSITION : AMPM_FORWARD_WITHSECOND);
1681         amPmId_.reset();
1682         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1683         host->MarkModifyDone();
1684     } else if (!GetHour24() && host->GetChildren().size() == CHILD_WITHOUT_AMPM_SIZE + 1) {
1685         CreateAmPmNode();
1686     }
1687     if ((GetHour24() && host->GetChildren().size() != CHILD_WITHOUT_AMPM_SIZE + 1) ||
1688         (!GetHour24() && host->GetChildren().size() != CHILD_WITH_AMPM_SIZE + 1)) {
1689         return;
1690     }
1691     if (language_ == "ug") {
1692         UpdateAllChildNodeForUg();
1693         return;
1694     }
1695     auto children = host->GetChildren();
1696     auto iter = children.begin();
1697     CHECK_NULL_VOID(*iter);
1698     auto amPmNode = GetAmPmNode(iter);
1699     auto hourNode = GetHourNode(iter);
1700     auto minuteNode = GetMinuteNode(iter);
1701     auto secondNode = GetSecondNode(iter);
1702     allChildNode_["amPm"] = amPmNode;
1703     allChildNode_["hour"] = hourNode;
1704     allChildNode_["minute"] = minuteNode;
1705     allChildNode_["second"] = secondNode;
1706 }
1707 
GetAmPmNode(std::list<RefPtr<UINode>>::iterator & iter)1708 RefPtr<FrameNode> TimePickerRowPattern::GetAmPmNode(std::list<RefPtr<UINode>>::iterator& iter)
1709 {
1710     if (GetHour24()) {
1711         return nullptr;
1712     }
1713     auto amPm = (*iter);
1714     if (amPmTimeOrder_ == "01") {
1715         if (!hasSecond_) {
1716             std::advance(iter, AMPM_FORWARD_WITHOUTSECOND);
1717             amPm = (*iter);
1718             std::advance(iter, AMPM_BACKWARD_WITHOUTSECOND);
1719         } else {
1720             std::advance(iter, AMPM_FORWARD_WITHSECOND);
1721             amPm = (*iter);
1722             std::advance(iter, AMPM_BACKWARD_WITHSECOND);
1723         }
1724     } else {
1725         iter++;
1726     }
1727     CHECK_NULL_RETURN(amPm, nullptr);
1728     auto amPmStackNode = DynamicCast<FrameNode>(amPm);
1729     auto amPmBlendNode = DynamicCast<FrameNode>(amPmStackNode->GetLastChild());
1730     CHECK_NULL_RETURN(amPmBlendNode, nullptr);
1731     auto amPmNode = DynamicCast<FrameNode>(amPmBlendNode->GetLastChild());
1732     CHECK_NULL_RETURN(amPmNode, nullptr);
1733     return amPmNode;
1734 }
1735 
GetHourNode(std::list<RefPtr<UINode>>::iterator & iter)1736 RefPtr<FrameNode> TimePickerRowPattern::GetHourNode(std::list<RefPtr<UINode>>::iterator& iter)
1737 {
1738     auto hour = *iter;
1739     CHECK_NULL_RETURN(hour, nullptr);
1740     auto hourStackNode = DynamicCast<FrameNode>(hour);
1741     auto hourBlendNode = DynamicCast<FrameNode>(hourStackNode->GetLastChild());
1742     CHECK_NULL_RETURN(hourBlendNode, nullptr);
1743     auto hourNode = DynamicCast<FrameNode>(hourBlendNode->GetLastChild());
1744     CHECK_NULL_RETURN(hourNode, nullptr);
1745     iter++;
1746     return hourNode;
1747 }
1748 
GetMinuteNode(std::list<RefPtr<UINode>>::iterator & iter)1749 RefPtr<FrameNode> TimePickerRowPattern::GetMinuteNode(std::list<RefPtr<UINode>>::iterator& iter)
1750 {
1751     auto minute = *iter;
1752     CHECK_NULL_RETURN(minute, nullptr);
1753     auto minuteStackNode = DynamicCast<FrameNode>(minute);
1754     auto minuteBlendNode = DynamicCast<FrameNode>(minuteStackNode->GetLastChild());
1755     CHECK_NULL_RETURN(minuteBlendNode, nullptr);
1756     auto minuteNode = DynamicCast<FrameNode>(minuteBlendNode->GetLastChild());
1757     CHECK_NULL_RETURN(minuteNode, nullptr);
1758     iter++;
1759     return minuteNode;
1760 }
1761 
GetSecondNode(std::list<RefPtr<UINode>>::iterator & iter)1762 RefPtr<FrameNode> TimePickerRowPattern::GetSecondNode(std::list<RefPtr<UINode>>::iterator& iter)
1763 {
1764     if (!hasSecond_) {
1765         return nullptr;
1766     }
1767     auto second = *iter;
1768     CHECK_NULL_RETURN(second, nullptr);
1769     auto secondStackNode = DynamicCast<FrameNode>(second);
1770     auto secondBlendNode = DynamicCast<FrameNode>(secondStackNode->GetLastChild());
1771     CHECK_NULL_RETURN(secondBlendNode, nullptr);
1772     auto secondNode = DynamicCast<FrameNode>(secondBlendNode->GetLastChild());
1773     CHECK_NULL_RETURN(secondNode, nullptr);
1774     if (language_ == "ug") {
1775         iter++;
1776     }
1777     return secondNode;
1778 }
1779 
UpdateAllChildNodeForUg()1780 void TimePickerRowPattern::UpdateAllChildNodeForUg()
1781 {
1782     auto host = GetHost();
1783     CHECK_NULL_VOID(host);
1784     auto children = host->GetChildren();
1785     auto iter = children.begin();
1786     CHECK_NULL_VOID(*iter);
1787     RefPtr<FrameNode> amPmNode;
1788     if (!GetHour24()) {
1789         auto amPm = (*iter);
1790         CHECK_NULL_VOID(amPm);
1791         auto amPmStackNode = DynamicCast<FrameNode>(amPm);
1792         amPmNode = DynamicCast<FrameNode>(amPmStackNode->GetLastChild()->GetLastChild());
1793         CHECK_NULL_VOID(amPmNode);
1794         iter++;
1795     }
1796     auto secondNode = GetSecondNode(iter);
1797     auto minuteNode = GetMinuteNode(iter);
1798     auto hourNode = GetHourNode(iter);
1799     allChildNode_["amPm"] = amPmNode;
1800     allChildNode_["hour"] = hourNode;
1801     allChildNode_["minute"] = minuteNode;
1802     allChildNode_["second"] = secondNode;
1803 }
1804 
HandleHour12Change(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1805 void TimePickerRowPattern::HandleHour12Change(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1806 {
1807     UpdateAllChildNode();
1808     auto amPm = allChildNode_["amPm"].Upgrade();
1809     CHECK_NULL_VOID(amPm);
1810     auto amPmPickerColumnPattern = amPm->GetPattern<TimePickerColumnPattern>();
1811 
1812     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && isAdd && index == 11) { // hour index start from 0 to 11
1813         amPmPickerColumnPattern->SetCurrentIndex(1);                               // add to PM's index
1814         resultTags.emplace_back(amPm);
1815         return;
1816     }
1817     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && !isAdd && index == 10) { // reduce to 11 hour (index is 10)
1818         amPmPickerColumnPattern->SetCurrentIndex(0);                                // change to AM whose index is 0
1819         resultTags.emplace_back(amPm);
1820         return;
1821     }
1822     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && isAdd && index == 11) {
1823         amPmPickerColumnPattern->SetCurrentIndex(0); // is PM (index is 1) and last hour (index is 11)
1824         resultTags.emplace_back(amPm);               // change to PM (index is 0)
1825         return;
1826     }
1827     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && !isAdd && index == 10) { // reduce to 11 hour(index is 10)
1828         amPmPickerColumnPattern->SetCurrentIndex(1);                                // change to PM
1829         resultTags.emplace_back(amPm);
1830         return;
1831     }
1832 }
1833 
GetAmPmHour(uint32_t hourOf24) const1834 uint32_t TimePickerRowPattern::GetAmPmHour(uint32_t hourOf24) const
1835 {
1836     if (hourOf24 == 0) {
1837         return AM_PM_HOUR_12;                         // AM 12:00 means 00:00 in 24 hour style
1838     }
1839     if (1 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11) { // 00:00 to 11:00 is the same for any hour style
1840         return hourOf24;
1841     }
1842     if (hourOf24 == AM_PM_HOUR_12) { // 12:00 means PM start hour
1843         return AM_PM_HOUR_12;        // 12 PM
1844     }                                // hour from 13 to 23
1845     return hourOf24 - AM_PM_HOUR_12; // need reduce 12 to 12 hours style
1846 }
1847 
ParseHourOf24(uint32_t hourOf24) const1848 uint32_t TimePickerRowPattern::ParseHourOf24(uint32_t hourOf24) const
1849 {
1850     return (hourOf24 <= AM_PM_HOUR_11)? hourOf24 : (hourOf24 - AM_PM_HOUR_12);
1851 }
1852 
IsAmHour(uint32_t hourOf24) const1853 bool TimePickerRowPattern::IsAmHour(uint32_t hourOf24) const
1854 {
1855     return (0 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11); // 00:00 to 11:00 is AM hour
1856 }
1857 
GetAmFormatString() const1858 std::string TimePickerRowPattern::GetAmFormatString() const
1859 {
1860     if (vecAmPm_.empty()) {
1861         return "AM";
1862     }
1863     return vecAmPm_[0]; // first index is AM
1864 }
1865 
GetPmFormatString() const1866 std::string TimePickerRowPattern::GetPmFormatString() const
1867 {
1868     if (vecAmPm_.size() < 2) { // size need to be 2 for AM and PM
1869         return "PM";
1870     }
1871     return vecAmPm_[1]; // second index is PM
1872 }
1873 
GetHourFormatString(uint32_t hour) const1874 std::string TimePickerRowPattern::GetHourFormatString(uint32_t hour) const
1875 {
1876     DateTime time;
1877     time.minute = hour; // minute range [0, 59], hour range [0, 23]; hour range is in minute range.
1878     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1879         if (Localization::GetInstance()->HasZeroHour()) {
1880             return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
1881         }
1882     } else {
1883         if (((GetPrefixHour() == ZeroPrefixType::AUTO) && GetHour24()) ||
1884             GetPrefixHour() == ZeroPrefixType::SHOW) {
1885             return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
1886         }
1887     }
1888     return Localization::GetInstance()->FormatDateTime(time, "m");
1889 }
1890 
GetMinuteFormatString(uint32_t minute) const1891 std::string TimePickerRowPattern::GetMinuteFormatString(uint32_t minute) const
1892 {
1893     DateTime time;
1894     time.minute = minute;
1895     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1896         return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
1897     } else {
1898         return Localization::GetInstance()->FormatDateTime(time, "m");
1899     }
1900 }
1901 
GetSecondFormatString(uint32_t second) const1902 std::string TimePickerRowPattern::GetSecondFormatString(uint32_t second) const
1903 {
1904     DateTime time;
1905     time.second = second;
1906     if (!Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
1907         return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "s"));
1908     } else {
1909         return Localization::GetInstance()->FormatDateTime(time, "s");
1910     }
1911 }
1912 
AddZeroPrefix(const std::string & value) const1913 std::string TimePickerRowPattern::AddZeroPrefix(const std::string& value) const
1914 {
1915     if (value.size() == 1 && '0' <= value[0] && value[0] <= '9') { // value is number in range [0, 9]
1916         return std::string("0") + value;                           // add prefix '0'
1917     }
1918     return value;
1919 }
1920 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)1921 void TimePickerRowPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1922 {
1923     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1924         auto pattern = wp.Upgrade();
1925         if (pattern) {
1926             return pattern->OnKeyEvent(event);
1927         }
1928         return false;
1929     };
1930     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1931 
1932     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
1933         auto pattern = wp.Upgrade();
1934         if (pattern) {
1935             pattern->GetInnerFocusPaintRect(paintRect);
1936         }
1937     };
1938     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
1939 }
1940 
SetDigitalCrownSensitivity(int32_t crownSensitivity)1941 void TimePickerRowPattern::SetDigitalCrownSensitivity(int32_t crownSensitivity)
1942 {
1943 #ifdef SUPPORT_DIGITAL_CROWN
1944     auto host = GetHost();
1945     CHECK_NULL_VOID(host);
1946     auto&& children = host->GetChildren();
1947     for (const auto& child : children) {
1948         auto stackNode = DynamicCast<FrameNode>(child);
1949         CHECK_NULL_VOID(stackNode);
1950         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
1951         CHECK_NULL_VOID(blendNode);
1952         auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
1953         CHECK_NULL_VOID(childNode);
1954         auto pickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
1955         CHECK_NULL_VOID(pickerColumnPattern);
1956         pickerColumnPattern->SetDigitalCrownSensitivity(crownSensitivity);
1957     }
1958 #endif
1959 }
1960 
PaintFocusState()1961 void TimePickerRowPattern::PaintFocusState()
1962 {
1963     auto host = GetHost();
1964     CHECK_NULL_VOID(host);
1965 
1966     RoundRect focusRect;
1967     GetInnerFocusPaintRect(focusRect);
1968 
1969     auto focusHub = host->GetFocusHub();
1970     CHECK_NULL_VOID(focusHub);
1971     focusHub->PaintInnerFocusState(focusRect);
1972 
1973     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
1974 }
1975 
CalcLeftTotalColumnWidth(const RefPtr<FrameNode> & host,float & leftTotalColumnWidth,float childSize)1976 void TimePickerRowPattern::CalcLeftTotalColumnWidth(
1977     const RefPtr<FrameNode>& host, float& leftTotalColumnWidth, float childSize)
1978 {
1979     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
1980     if (isRtl) {
1981         for (int32_t index = childSize - 1; index > focusKeyID_; --index) {
1982             auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1983             CHECK_NULL_VOID(stackChild);
1984             auto geometryNode = stackChild->GetGeometryNode();
1985             CHECK_NULL_VOID(geometryNode);
1986             leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
1987         }
1988     } else {
1989         for (int32_t index = 0; index < focusKeyID_; ++index) {
1990             auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
1991             CHECK_NULL_VOID(stackChild);
1992             auto geometryNode = stackChild->GetGeometryNode();
1993             CHECK_NULL_VOID(geometryNode);
1994             leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
1995         }
1996     }
1997 }
1998 
GetInnerFocusPaintRect(RoundRect & paintRect)1999 void TimePickerRowPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
2000 {
2001     auto host = GetHost();
2002     CHECK_NULL_VOID(host);
2003     auto childSize = static_cast<float>(host->GetChildren().size());
2004     CHECK_EQUAL_VOID(childSize, 0);
2005     auto leftTotalColumnWidth = 0.0f;
2006     CalcLeftTotalColumnWidth(host, leftTotalColumnWidth, childSize);
2007     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
2008     CHECK_NULL_VOID(stackChild);
2009     auto columnBlendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
2010     CHECK_NULL_VOID(columnBlendChild);
2011     auto pickerChild = DynamicCast<FrameNode>(columnBlendChild->GetLastChild());
2012     CHECK_NULL_VOID(pickerChild);
2013     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
2014     auto pipeline = PipelineBase::GetCurrentContext();
2015     CHECK_NULL_VOID(pipeline);
2016     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2017     CHECK_NULL_VOID(pickerTheme);
2018     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
2019 
2020     float paintRectWidth = columnWidth - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
2021     float paintRectHeight = dividerSpacing - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
2022     auto centerX = leftTotalColumnWidth + FOCUS_INTERVAL.ConvertToPx() + LINE_WIDTH.ConvertToPx();
2023     auto centerY = (host->GetGeometryNode()->GetFrameSize().Height() - dividerSpacing) / RATE +
2024         FOCUS_INTERVAL.ConvertToPx() + LINE_WIDTH.ConvertToPx();
2025 
2026     paintRect.SetRect(RectF(centerX, centerY, paintRectWidth, paintRectHeight));
2027     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
2028         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
2029     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
2030         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
2031     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
2032         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
2033     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
2034         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
2035 }
2036 
OnKeyEvent(const KeyEvent & event)2037 bool TimePickerRowPattern::OnKeyEvent(const KeyEvent& event)
2038 {
2039     if (event.action != KeyAction::DOWN) {
2040         return false;
2041     }
2042     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
2043         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
2044         event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
2045         return HandleDirectionKey(event.code);
2046     }
2047     return false;
2048 }
2049 
SetFocusDisable()2050 void TimePickerRowPattern::SetFocusDisable()
2051 {
2052     auto host = GetHost();
2053     CHECK_NULL_VOID(host);
2054 
2055     auto focusHub = host->GetFocusHub();
2056     CHECK_NULL_VOID(focusHub);
2057 
2058     focusHub->SetFocusable(false);
2059 }
2060 
SetFocusEnable()2061 void TimePickerRowPattern::SetFocusEnable()
2062 {
2063     auto host = GetHost();
2064     CHECK_NULL_VOID(host);
2065 
2066     auto focusHub = host->GetFocusHub();
2067     CHECK_NULL_VOID(focusHub);
2068 
2069     focusHub->SetFocusable(true);
2070 }
2071 
CheckFocusID(int32_t childSize)2072 bool TimePickerRowPattern::CheckFocusID(int32_t childSize)
2073 {
2074     if (focusKeyID_ > childSize - 1) {
2075         focusKeyID_ = childSize - 1;
2076         return false;
2077     }
2078     if (NeedAdaptForAging() && !GetIsShowInDatePickerDialog()) {
2079         if (GetCurrentPage() == 1) {
2080             if (focusKeyID_ < 1) {
2081                 focusKeyID_ = 1;
2082                 return false;
2083             }
2084         } else {
2085             if (focusKeyID_ != 0) {
2086                 focusKeyID_ = 0;
2087                 return false;
2088             }
2089         }
2090     } else {
2091         if (focusKeyID_ < 0) {
2092             focusKeyID_ = 0;
2093             return false;
2094         }
2095     }
2096     return true;
2097 }
2098 
ParseDirectionKey(RefPtr<FrameNode> & host,RefPtr<TimePickerColumnPattern> & pattern,KeyCode & code,int32_t currentIndex,uint32_t totalOptionCount,int32_t childSize)2099 bool TimePickerRowPattern::ParseDirectionKey(RefPtr<FrameNode>& host, RefPtr<TimePickerColumnPattern>& pattern,
2100     KeyCode& code, int32_t currentIndex, uint32_t totalOptionCount, int32_t childSize)
2101 {
2102     bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
2103     if (code == KeyCode::KEY_DPAD_UP || code == KeyCode::KEY_DPAD_DOWN) {
2104         auto index = (code == KeyCode::KEY_DPAD_UP) ? -1 : 1;
2105         pattern->SetCurrentIndex((totalOptionCount + currentIndex + index) % totalOptionCount);
2106         pattern->FlushCurrentOptions();
2107         pattern->HandleChangeCallback((code == KeyCode::KEY_DPAD_UP) ? false : true, true);
2108         pattern->HandleEventCallback(true);
2109         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
2110         return true;
2111     }
2112     if (code == KeyCode::KEY_MOVE_HOME) {
2113         pattern->SetCurrentIndex(1);
2114         pattern->InnerHandleScroll(false, false);
2115         return true;
2116     }
2117     if (code == KeyCode::KEY_MOVE_END) {
2118         pattern->SetCurrentIndex(totalOptionCount - UNOPTION_COUNT);
2119         pattern->InnerHandleScroll(true, false);
2120         return true;
2121     }
2122     if (code == KeyCode::KEY_DPAD_LEFT) {
2123         focusKeyID_ = isRtl ? (focusKeyID_ + 1) : (focusKeyID_ - 1);
2124         if (!CheckFocusID(childSize)) {
2125             return false;
2126         }
2127         PaintFocusState();
2128         return true;
2129     }
2130     if (code == KeyCode::KEY_DPAD_RIGHT) {
2131         focusKeyID_ = isRtl ? (focusKeyID_ - 1) : (focusKeyID_ + 1);
2132         if (!CheckFocusID(childSize)) {
2133             return false;
2134         }
2135         PaintFocusState();
2136         return true;
2137     }
2138     return false;
2139 }
2140 
HandleDirectionKey(KeyCode code)2141 bool TimePickerRowPattern::HandleDirectionKey(KeyCode code)
2142 {
2143     auto host = GetHost();
2144     CHECK_NULL_RETURN(host, false);
2145     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
2146     CHECK_NULL_RETURN(stackChild, false);
2147     auto childSize = host->GetChildren().size();
2148     auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild()->GetLastChild());
2149     CHECK_NULL_RETURN(pickerChild, false);
2150     auto pattern = pickerChild->GetPattern<TimePickerColumnPattern>();
2151     CHECK_NULL_RETURN(pattern, false);
2152     auto currentIndex = pattern->GetCurrentIndex();
2153     auto totalOptionCount = GetOptionCount(pickerChild);
2154     if (totalOptionCount == 0) {
2155         return false;
2156     }
2157     return ParseDirectionKey(host, pattern, code, currentIndex, totalOptionCount, static_cast<int32_t>(childSize));
2158 }
2159 
OnColorConfigurationUpdate()2160 void TimePickerRowPattern::OnColorConfigurationUpdate()
2161 {
2162     auto host = GetHost();
2163     CHECK_NULL_VOID(host);
2164     host->SetNeedCallChildrenUpdate(false);
2165     auto context = host->GetContext();
2166     CHECK_NULL_VOID(context);
2167     auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
2168     CHECK_NULL_VOID(pickerTheme);
2169     auto dialogTheme = context->GetTheme<DialogTheme>();
2170     CHECK_NULL_VOID(dialogTheme);
2171     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
2172     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
2173     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
2174     CHECK_NULL_VOID(pickerProperty);
2175     pickerProperty->UpdateColor(GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
2176     pickerProperty->UpdateDisappearColor(
2177         GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
2178     if (isPicker_) {
2179         return;
2180     }
2181     SetBackgroundColor(dialogTheme->GetBackgroundColor());
2182     auto buttonTitleNode = buttonTitleNode_.Upgrade();
2183     CHECK_NULL_VOID(buttonTitleNode);
2184     auto buttonTitleRenderContext = buttonTitleNode->GetRenderContext();
2185     CHECK_NULL_VOID(buttonTitleRenderContext);
2186     buttonTitleRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
2187     auto childText = buttonTitleNode->GetFirstChild();
2188     CHECK_NULL_VOID(childText);
2189     auto textTitleNode = DynamicCast<FrameNode>(childText);
2190     CHECK_NULL_VOID(textTitleNode);
2191     auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
2192     CHECK_NULL_VOID(textLayoutProperty);
2193     textLayoutProperty->UpdateTextColor(pickerTheme->GetTitleStyle().GetTextColor());
2194     auto contentRowNode = contentRowNode_.Upgrade();
2195     CHECK_NULL_VOID(contentRowNode);
2196     auto layoutRenderContext = contentRowNode->GetRenderContext();
2197     CHECK_NULL_VOID(layoutRenderContext);
2198     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) || !layoutRenderContext->IsUniRenderEnabled()) {
2199         layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
2200     }
2201     host->MarkModifyDone();
2202 }
2203 
OnThemeScopeUpdate(int32_t themeScopeId)2204 bool TimePickerRowPattern::OnThemeScopeUpdate(int32_t themeScopeId)
2205 {
2206     bool result = false;
2207     auto host = GetHost();
2208     CHECK_NULL_RETURN(host, result);
2209     host->SetNeedCallChildrenUpdate(false);
2210     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
2211     CHECK_NULL_RETURN(pickerProperty, result);
2212     // The following three attributes will be affected by withTheme.
2213     // If they are setted by user, then use the value by user set; Otherwise use the value from withTheme
2214     // When the "result" is true, mean to notify the framework to Re-render
2215     if ((!pickerProperty->HasColor()) || (!pickerProperty->HasDisappearColor()) ||
2216         (!pickerProperty->HasSelectedColor())) {
2217         result = true;
2218     }
2219     OnModifyDone();
2220     return result;
2221 }
2222 
NeedAdaptForAging()2223 bool TimePickerRowPattern::NeedAdaptForAging()
2224 {
2225     auto host = GetHost();
2226     CHECK_NULL_RETURN(host, false);
2227     auto pipeline = host->GetContext();
2228     CHECK_NULL_RETURN(pipeline, false);
2229     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2230     CHECK_NULL_RETURN(pickerTheme, false);
2231 
2232     if (GreatOrEqual(pipeline->GetFontScale(), pickerTheme->GetMaxOneFontScale()) &&
2233         Dimension(pipeline->GetRootHeight()).ConvertToVp() > pickerTheme->GetDeviceHeightLimit()) {
2234         return true;
2235     }
2236     return false;
2237 }
2238 
UpdateUserSetSelectColor()2239 void TimePickerRowPattern::UpdateUserSetSelectColor()
2240 {
2241     CHECK_EQUAL_VOID(IsCircle(), false);
2242     isUserSetSelectColor_ = true;
2243     for (auto iter = allChildNode_.begin(); iter != allChildNode_.end(); iter++) {
2244         auto columnNode = iter->second.Upgrade();
2245         if (columnNode) {
2246             auto pattern = columnNode->GetPattern<TimePickerColumnPattern>();
2247             if (pattern) {
2248                 pattern->UpdateUserSetSelectColor();
2249             }
2250         }
2251     }
2252 }
2253 
2254 } // namespace OHOS::Ace::NG
2255