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