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