• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/pattern/time_picker/timepicker_row_pattern.h"
17 #include <cstdint>
18 
19 #include "base/geometry/ng/size_t.h"
20 #include "base/utils/utils.h"
21 #include "core/components/picker/picker_theme.h"
22 #include "core/components_ng/pattern/button/button_pattern.h"
23 #include "core/components_ng/pattern/stack/stack_pattern.h"
24 #include "core/components_ng/pattern/text/text_pattern.h"
25 #include "core/components_ng/pattern/time_picker/toss_animation_controller.h"
26 #include "core/components_v2/inspector/inspector_constants.h"
27 #include "core/pipeline_ng/ui_task_scheduler.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 // TODO timepicker style modification
32 constexpr int32_t CHILD_WITH_AMPM_SIZE = 3;
33 constexpr int32_t CHILD_WITHOUT_AMPM_SIZE = 2;
34 constexpr uint32_t AM_PM_HOUR_12 = 12;
35 constexpr uint32_t AM_PM_HOUR_11 = 11;
36 const int32_t AM_PM_COUNT = 3;
37 const Dimension PRESS_INTERVAL = 4.0_vp;
38 const Dimension PRESS_RADIUS = 8.0_vp;
39 const int32_t UNOPTION_COUNT = 2;
40 } // namespace
41 
OnAttachToFrameNode()42 void TimePickerRowPattern::OnAttachToFrameNode()
43 {
44     auto host = GetHost();
45     CHECK_NULL_VOID(host);
46     host->GetRenderContext()->SetClipToFrame(true);
47     host->GetRenderContext()->UpdateClipEdge(true);
48 }
49 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)50 bool TimePickerRowPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
51 {
52     CHECK_NULL_RETURN_NOLOG(config.frameSizeChange, false);
53     CHECK_NULL_RETURN(dirty, false);
54     SetButtonIdeaSize();
55     return true;
56 }
57 
SetButtonIdeaSize()58 void TimePickerRowPattern::SetButtonIdeaSize()
59 {
60     auto host = GetHost();
61     CHECK_NULL_VOID(host);
62     auto context = host->GetContext();
63     CHECK_NULL_VOID(context);
64     auto pickerTheme = context->GetTheme<PickerTheme>();
65     CHECK_NULL_VOID(pickerTheme);
66     auto children = host->GetChildren();
67     auto height = pickerTheme->GetDividerSpacing();
68     auto width = host->GetGeometryNode()->GetFrameSize().Width() / static_cast<float>(children.size());
69     auto defaultWidth = height.ConvertToPx() * 2;
70     if (width > defaultWidth) {
71         width = static_cast<float>(defaultWidth);
72     }
73     for (const auto& child : children) {
74         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
75         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
76         buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
77         buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
78         buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
79         buttonLayoutProperty->UpdateUserDefinedIdealSize(
80             CalcSize(CalcLength(width - PRESS_INTERVAL.ConvertToPx()), CalcLength(height - PRESS_INTERVAL)));
81         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
82         buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
83         buttonNode->MarkModifyDone();
84     }
85 }
86 
OnModifyDone()87 void TimePickerRowPattern::OnModifyDone()
88 {
89     auto host = GetHost();
90     CHECK_NULL_VOID(host);
91     CreateAmPmNode();
92     OnColumnsBuilding();
93     FlushColumn();
94     InitDisabled();
95     SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag, bool add, uint32_t index, bool notify) {
96         auto refPtr = weak.Upgrade();
97         CHECK_NULL_VOID_NOLOG(refPtr);
98         refPtr->HandleColumnChange(tag, add, index, notify);
99     });
100     SetEventCallback([weak = WeakClaim(this)](bool refresh) {
101         auto refPtr = weak.Upgrade();
102         CHECK_NULL_VOID_NOLOG(refPtr);
103         refPtr->FireChangeEvent(refresh);
104     });
105     auto focusHub = host->GetFocusHub();
106     if (focusHub) {
107         InitOnKeyEvent(focusHub);
108     }
109     if (HasTitleNode()) {
110         auto textTitleNode = FrameNode::GetOrCreateFrameNode(
111             V2::TEXT_ETS_TAG, GetTitleId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
112         auto str = GetDialogTitleDate();
113         CHECK_NULL_VOID(textTitleNode);
114         auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
115         CHECK_NULL_VOID(textLayoutProperty);
116         textLayoutProperty->UpdateContent(str.ToString(false));
117     }
118     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
119 }
120 
InitDisabled()121 void TimePickerRowPattern::InitDisabled()
122 {
123     auto host = GetHost();
124     CHECK_NULL_VOID(host);
125     auto eventHub = host->GetEventHub<EventHub>();
126     CHECK_NULL_VOID(eventHub);
127     auto renderContext = host->GetRenderContext();
128     enabled_ = eventHub->IsEnabled();
129     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
130 }
131 
CreateAmPmNode()132 void TimePickerRowPattern::CreateAmPmNode()
133 {
134     auto host = GetHost();
135     CHECK_NULL_VOID(host);
136     auto context = host->GetContext();
137     CHECK_NULL_VOID(context);
138     auto pickerTheme = context->GetTheme<PickerTheme>();
139     CHECK_NULL_VOID(pickerTheme);
140     auto heigth = pickerTheme->GetDividerSpacing();
141     if (!GetHour24() && !HasAmPmNode()) {
142         auto amPmColumnNode = FrameNode::GetOrCreateFrameNode(
143             V2::COLUMN_ETS_TAG, GetAmPmId(), []() { return AceType::MakeRefPtr<TimePickerColumnPattern>(); });
144         CHECK_NULL_VOID(amPmColumnNode);
145         for (uint32_t index = 0; index < AM_PM_COUNT; index++) {
146             auto textNode = FrameNode::CreateFrameNode(
147                 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
148             CHECK_NULL_VOID(textNode);
149             textNode->MountToParent(amPmColumnNode);
150         }
151         SetColumn(amPmColumnNode);
152         auto stackAmPmNode = FrameNode::GetOrCreateFrameNode(V2::STACK_ETS_TAG,
153             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<StackPattern>(); });
154         auto buttonNode = FrameNode::GetOrCreateFrameNode(V2::BUTTON_ETS_TAG,
155             ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<ButtonPattern>(); });
156         buttonNode->MountToParent(stackAmPmNode);
157         auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
158         amPmColumnNode->MountToParent(stackAmPmNode);
159         auto layoutProperty = stackAmPmNode->GetLayoutProperty<LayoutProperty>();
160         layoutProperty->UpdateAlignment(Alignment::CENTER);
161         layoutProperty->UpdateLayoutWeight(1);
162         stackAmPmNode->MountToParent(host, 0);
163         if (SetAmPmButtonIdeaSize() > 0) {
164             auto buttonLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
165             buttonLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
166             buttonLayoutProperty->UpdateType(ButtonType::NORMAL);
167             buttonLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
168             buttonLayoutProperty->UpdateUserDefinedIdealSize(
169                 CalcSize(CalcLength(SetAmPmButtonIdeaSize()), CalcLength(heigth - PRESS_INTERVAL)));
170             auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
171             buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
172             buttonNode->MarkModifyDone();
173             buttonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
174         }
175         host->MarkModifyDone();
176         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
177     }
178 }
179 
SetAmPmButtonIdeaSize()180 double TimePickerRowPattern::SetAmPmButtonIdeaSize()
181 {
182     auto host = GetHost();
183     CHECK_NULL_RETURN(host, 0);
184     auto children = host->GetChildren();
185     float width = 0.0f;
186     for (const auto& child : children) {
187         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
188         CHECK_NULL_RETURN(buttonNode, 0);
189         width = buttonNode->GetGeometryNode()->GetFrameSize().Width();
190     }
191     if (width > 0) {
192         return width;
193     }
194     return 0;
195 }
SetEventCallback(EventCallback && value)196 void TimePickerRowPattern::SetEventCallback(EventCallback&& value)
197 {
198     auto host = GetHost();
199     CHECK_NULL_VOID(host);
200     auto children = host->GetChildren();
201     for (const auto& child : children) {
202         auto stackNode = DynamicCast<FrameNode>(child);
203         CHECK_NULL_VOID(stackNode);
204         auto childNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
205         CHECK_NULL_VOID(childNode);
206         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
207         CHECK_NULL_VOID(timePickerColumnPattern);
208         timePickerColumnPattern->SetEventCallback(std::move(value));
209     }
210 }
211 
FireChangeEvent(bool refresh)212 void TimePickerRowPattern::FireChangeEvent(bool refresh)
213 {
214     if (refresh) {
215         auto timePickerEventHub = GetEventHub<TimePickerEventHub>();
216         CHECK_NULL_VOID(timePickerEventHub);
217         auto str = GetSelectedObject(true);
218         auto info = std::make_shared<DatePickerChangeEvent>(str);
219         timePickerEventHub->FireChangeEvent(info.get());
220         timePickerEventHub->FireDialogChangeEvent(str);
221     }
222 }
223 
GetSelectedObject(bool isColumnChange,int32_t status)224 std::string TimePickerRowPattern::GetSelectedObject(bool isColumnChange, int32_t status)
225 {
226     auto time = selectedTime_;
227     if (isColumnChange) {
228         time = GetCurrentTime();
229     }
230     return time.ToString(true, hasSecond_, status);
231 }
232 
GetCurrentTime()233 PickerTime TimePickerRowPattern::GetCurrentTime()
234 {
235     PickerTime time;
236     UpdateAllChildNode();
237     auto amPmColumn = allChildNode_["amPm"];
238     auto hourColumn = allChildNode_["hour"];
239     auto minuteColumn = allChildNode_["minute"];
240     CHECK_NULL_RETURN(hourColumn, time);
241     CHECK_NULL_RETURN(minuteColumn, time);
242     auto hourPickerColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
243     CHECK_NULL_RETURN(hourPickerColumnPattern, time);
244     auto minutePickerColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
245     CHECK_NULL_RETURN(minutePickerColumnPattern, time);
246 
247     if (GetHour24()) {
248         time.SetHour(hourPickerColumnPattern->GetCurrentIndex()); // hour from 0 to 23, index from 0 to 23
249     } else if (amPmColumn) {
250         auto amPmPickerColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
251         CHECK_NULL_RETURN(amPmPickerColumnPattern, time);
252         time.SetHour(GetHourFromAmPm(
253             amPmPickerColumnPattern->GetCurrentIndex() == 0, hourPickerColumnPattern->GetCurrentIndex() + 1));
254     } else {
255         LOGE("AM PM column is null.");
256     }
257 
258     time.SetMinute(minutePickerColumnPattern->GetCurrentIndex()); // minute from 0 to 59, index from 0 to 59
259     return time;
260 }
261 
GetHourFromAmPm(bool isAm,uint32_t amPmhour) const262 uint32_t TimePickerRowPattern::GetHourFromAmPm(bool isAm, uint32_t amPmhour) const
263 {
264     if (isAm) {
265         if (amPmhour == AM_PM_HOUR_12) { // AM 12:00 means 00:00
266             return 0;
267         }
268         return amPmhour;
269     }
270     if (amPmhour == AM_PM_HOUR_12) { // PM 12 means 12:00
271         return AM_PM_HOUR_12;
272     }
273     return amPmhour + AM_PM_HOUR_12; // need add 12 hour to 24 hours style
274 }
275 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)276 void TimePickerRowPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, bool needNotify)
277 {
278     std::vector<RefPtr<FrameNode>> tags;
279     for (const auto& tag : tags) {
280         auto iter = std::find_if(timePickerColumns_.begin(), timePickerColumns_.end(),
281             [&tag](const RefPtr<FrameNode>& column) { return column->GetId() == tag->GetId(); });
282         if (iter != timePickerColumns_.end()) {
283             auto timePickerColumnPattern = (*iter)->GetPattern<TimePickerColumnPattern>();
284             CHECK_NULL_VOID(timePickerColumnPattern);
285             timePickerColumnPattern->FlushCurrentOptions();
286         }
287     }
288 }
289 
OnLanguageConfigurationUpdate()290 void TimePickerRowPattern::OnLanguageConfigurationUpdate()
291 {
292     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
293     CHECK_NULL_VOID(buttonConfirmNode);
294     auto confirmNode = buttonConfirmNode->GetFirstChild();
295     auto confirmNodeLayout = AceType::DynamicCast<FrameNode>(confirmNode)->GetLayoutProperty<TextLayoutProperty>();
296     confirmNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.ok"));
297 
298     auto buttonCancelNode = weakButtonCancel_.Upgrade();
299     CHECK_NULL_VOID(buttonCancelNode);
300     auto cancelNode = buttonCancelNode->GetFirstChild();
301     auto cancelNodeLayout = AceType::DynamicCast<FrameNode>(cancelNode)->GetLayoutProperty<TextLayoutProperty>();
302     cancelNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.cancel"));
303     FlushAmPmFormatString();
304 }
305 
FlushAmPmFormatString()306 void TimePickerRowPattern::FlushAmPmFormatString()
307 {
308     auto it = std::find(vecAmPm_.begin(), vecAmPm_.end(), "AM");
309     if (it != vecAmPm_.end()) {
310         vecAmPm_.clear();
311         vecAmPm_ = Localization::GetInstance()->GetAmPmStrings();
312         std::string am = vecAmPm_[0];
313         vecAmPm_.emplace_back(am);
314         std::string pm = vecAmPm_[1];
315         vecAmPm_.emplace_back(pm);
316     } else {
317         vecAmPm_.clear();
318         vecAmPm_.emplace_back("AM");
319         vecAmPm_.emplace_back("PM");
320     }
321 }
322 
SetChangeCallback(ColumnChangeCallback && value)323 void TimePickerRowPattern::SetChangeCallback(ColumnChangeCallback&& value)
324 {
325     auto host = GetHost();
326     CHECK_NULL_VOID(host);
327     auto children = host->GetChildren();
328     for (const auto& child : children) {
329         auto stackNode = DynamicCast<FrameNode>(child);
330         CHECK_NULL_VOID(stackNode);
331         auto childNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
332         CHECK_NULL_VOID(childNode);
333         auto timePickerColumnPattern = childNode->GetPattern<TimePickerColumnPattern>();
334         CHECK_NULL_VOID(timePickerColumnPattern);
335         timePickerColumnPattern->SetChangeCallback(std::move(value));
336     }
337 }
338 
FlushColumn()339 void TimePickerRowPattern::FlushColumn()
340 {
341     UpdateAllChildNode();
342     auto amPmColumn = allChildNode_["amPm"];
343     auto hourColumn = allChildNode_["hour"];
344     if (GetHour24()) {
345         CHECK_NULL_VOID(hourColumn);
346         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
347         CHECK_NULL_VOID(hourColumnPattern);
348         hourColumnPattern->SetOptions(GetOptionsCount());
349         hourColumnPattern->SetShowCount(GetShowCount());
350         hourColumnPattern->FlushCurrentOptions();
351     } else if (amPmColumn) {
352         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
353         CHECK_NULL_VOID(amPmColumnPattern);
354         amPmColumnPattern->SetShowCount(AM_PM_COUNT);
355         amPmColumnPattern->FlushCurrentOptions();
356 
357         CHECK_NULL_VOID(hourColumn);
358         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
359         CHECK_NULL_VOID(hourColumnPattern);
360         hourColumnPattern->SetOptions(GetOptionsCount());
361         hourColumnPattern->SetShowCount(GetShowCount());
362         hourColumnPattern->FlushCurrentOptions();
363     }
364 
365     auto minuteColumn = allChildNode_["minute"];
366     CHECK_NULL_VOID(minuteColumn);
367     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
368     CHECK_NULL_VOID(minuteColumnPattern);
369     minuteColumnPattern->SetShowCount(GetShowCount());
370     minuteColumnPattern->FlushCurrentOptions();
371 }
372 
OnDataLinking(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)373 void TimePickerRowPattern::OnDataLinking(
374     const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
375 {
376     CHECK_NULL_VOID(tag);
377     auto hourNode = allChildNode_["hour"];
378     CHECK_NULL_VOID(hourNode);
379     if (tag->GetId() != hourNode->GetId()) {
380         return;
381     }
382 
383     if (!GetHour24()) {
384         HandleHour12Change(isAdd, index, resultTags);
385     }
386 }
387 
GetOptionsValue(const RefPtr<FrameNode> & frameNode,uint32_t optionIndex)388 const std::string& TimePickerRowPattern::GetOptionsValue(const RefPtr<FrameNode>& frameNode, uint32_t optionIndex)
389 {
390     UpdateAllChildNode();
391     if (frameNode == allChildNode_["amPm"]) {
392         return options_[allChildNode_["amPm"]][optionIndex];
393     }
394     bool isHour12 = !GetHour24();
395     auto isHourNode = frameNode == allChildNode_["hour"];
396     if (options_.find(frameNode) == options_.end()) {
397         options_[frameNode] = std::unordered_map<uint32_t, std::string>();
398     }
399     if (options_[frameNode].find(optionIndex) == options_[frameNode].end()) {
400         options_[frameNode][optionIndex] =
401             isHourNode ? GetHourFormatString(optionIndex + isHour12) : GetMinuteFormatString(optionIndex);
402     }
403     return options_[frameNode][optionIndex];
404 }
405 
OnColumnsBuilding()406 void TimePickerRowPattern::OnColumnsBuilding()
407 {
408     HandleHourColumnBuilding();
409 
410     UpdateAllChildNode();
411     auto minuteColumn = allChildNode_["minute"];
412     CHECK_NULL_VOID(minuteColumn);
413     auto minuteColumnPattern = minuteColumn->GetPattern<TimePickerColumnPattern>();
414     CHECK_NULL_VOID(minuteColumnPattern);
415     optionsTotalCount_[minuteColumn] = 0;
416 
417     for (uint32_t minute = 0; minute <= 59; ++minute) { // time's minute from 0 to 59
418         if (minute == selectedTime_.GetMinute()) {
419             minuteColumnPattern->SetCurrentIndex(minute);
420         }
421         optionsTotalCount_[minuteColumn]++;
422     }
423     minuteColumnPattern->SetOptions(GetOptionsCount());
424 }
425 
HandleHourColumnBuilding()426 void TimePickerRowPattern::HandleHourColumnBuilding()
427 {
428     UpdateAllChildNode();
429     auto amPmColumn = allChildNode_["amPm"];
430     auto hourColumn = allChildNode_["hour"];
431     optionsTotalCount_[hourColumn] = 0;
432     if (GetHour24()) {
433         CHECK_NULL_VOID(hourColumn);
434         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
435         CHECK_NULL_VOID(hourColumnPattern);
436         for (uint32_t hour = 0; hour <= 23; ++hour) { // time's hour from 0 to 23.
437             if (hour == selectedTime_.GetHour()) {
438                 hourColumnPattern->SetCurrentIndex(hour);
439             }
440             optionsTotalCount_[hourColumn]++;
441         }
442         hourColumnPattern->SetOptions(GetOptionsCount());
443         hourColumn->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
444     } else if (amPmColumn) {
445         CHECK_NULL_VOID(amPmColumn);
446         CHECK_NULL_VOID(hourColumn);
447         auto amPmColumnPattern = amPmColumn->GetPattern<TimePickerColumnPattern>();
448         CHECK_NULL_VOID(amPmColumnPattern);
449         auto hourColumnPattern = hourColumn->GetPattern<TimePickerColumnPattern>();
450         CHECK_NULL_VOID(hourColumnPattern);
451         options_[amPmColumn][0] = GetAmFormatString();
452         options_[amPmColumn][1] = GetPmFormatString();
453 
454         if (IsAmHour(selectedTime_.GetHour())) {
455             amPmColumnPattern->SetCurrentIndex(0); // AM's index
456         } else {
457             amPmColumnPattern->SetCurrentIndex(1); // PM's index
458         }
459         optionsTotalCount_[amPmColumn] = CHILD_WITHOUT_AMPM_SIZE;
460         auto selectedHour = GetAmPmHour(selectedTime_.GetHour());
461         for (uint32_t hour = 1; hour <= AM_PM_HOUR_12; ++hour) { // AM_PM hour start from 1 to 12
462             if (hour == selectedHour) {
463                 hourColumnPattern->SetCurrentIndex(hour - 1);
464             }
465             optionsTotalCount_[hourColumn]++;
466         }
467         amPmColumnPattern->SetOptions(GetOptionsCount());
468         hourColumnPattern->SetOptions(GetOptionsCount());
469     } else {
470         LOGE("AM PM column is null.");
471     }
472 }
473 
UpdateAllChildNode()474 void TimePickerRowPattern::UpdateAllChildNode()
475 {
476     auto host = GetHost();
477     CHECK_NULL_VOID(host);
478     if (GetHour24() && host->GetChildren().size() == CHILD_WITH_AMPM_SIZE) {
479         host->RemoveChildAtIndex(0);
480         amPmId_.reset();
481         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
482         host->MarkModifyDone();
483     } else if (!GetHour24() && host->GetChildren().size() == CHILD_WITHOUT_AMPM_SIZE) {
484         CreateAmPmNode();
485     }
486     if (GetHour24() && host->GetChildren().size() != CHILD_WITHOUT_AMPM_SIZE) {
487         return;
488     }
489 
490     if (!GetHour24() && host->GetChildren().size() != CHILD_WITH_AMPM_SIZE) {
491         return;
492     }
493     auto children = host->GetChildren();
494     auto iter = children.begin();
495     CHECK_NULL_VOID(*iter);
496     if (!GetHour24()) {
497         auto amPm = (*iter);
498         CHECK_NULL_VOID(amPm);
499         iter++;
500         auto hour = *iter;
501         CHECK_NULL_VOID(hour);
502         iter++;
503         auto minute = *iter;
504         CHECK_NULL_VOID(minute);
505         auto amPmStackNode = DynamicCast<FrameNode>(amPm);
506         auto amPmNode = DynamicCast<FrameNode>(amPmStackNode->GetLastChild());
507         auto hourStackNode = DynamicCast<FrameNode>(hour);
508         auto hourNode = DynamicCast<FrameNode>(hourStackNode->GetLastChild());
509         auto minuteStackNode = DynamicCast<FrameNode>(minute);
510         auto minuteNode = DynamicCast<FrameNode>(minuteStackNode->GetLastChild());
511         CHECK_NULL_VOID(amPmNode);
512         CHECK_NULL_VOID(hourNode);
513         CHECK_NULL_VOID(minuteNode);
514         allChildNode_["amPm"] = amPmNode;
515         allChildNode_["hour"] = hourNode;
516         allChildNode_["minute"] = minuteNode;
517     } else {
518         auto hour = *iter;
519         CHECK_NULL_VOID(hour);
520         iter++;
521         auto minute = *iter;
522         CHECK_NULL_VOID(minute);
523         auto hourStackNode = DynamicCast<FrameNode>(hour);
524         auto hourNode = DynamicCast<FrameNode>(hourStackNode->GetLastChild());
525         auto minuteStackNode = DynamicCast<FrameNode>(minute);
526         auto minuteNode = DynamicCast<FrameNode>(minuteStackNode->GetLastChild());
527         CHECK_NULL_VOID(hourNode);
528         CHECK_NULL_VOID(minuteNode);
529         allChildNode_["hour"] = hourNode;
530         allChildNode_["minute"] = minuteNode;
531     }
532 }
533 
HandleHour12Change(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)534 void TimePickerRowPattern::HandleHour12Change(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
535 {
536     UpdateAllChildNode();
537     auto amPm = allChildNode_["amPm"];
538     CHECK_NULL_VOID(amPm);
539     auto amPmPickerColumnPattern = amPm->GetPattern<TimePickerColumnPattern>();
540 
541     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && isAdd && index == 11) { // hour index start from 0 to 11
542         amPmPickerColumnPattern->SetCurrentIndex(1);                               // add to PM's index
543         resultTags.emplace_back(amPm);
544         return;
545     }
546     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && !isAdd && index == 10) { // reduce to 11 hour (index is 10)
547         amPmPickerColumnPattern->SetCurrentIndex(0);                                // change to AM whose index is 0
548         resultTags.emplace_back(amPm);
549         return;
550     }
551     if (amPmPickerColumnPattern->GetCurrentIndex() == 1 && isAdd && index == 11) {
552         amPmPickerColumnPattern->SetCurrentIndex(0); // is PM (index is 1) and last hour (index is 11)
553         resultTags.emplace_back(amPm);               // change to PM (index is 0)
554         return;
555     }
556     if (amPmPickerColumnPattern->GetCurrentIndex() == 0 && !isAdd && index == 10) { // reduce to 11 hour(index is 10)
557         amPmPickerColumnPattern->SetCurrentIndex(1);                                // change to PM
558         resultTags.emplace_back(amPm);
559         return;
560     }
561 }
562 
GetAmPmHour(uint32_t hourOf24) const563 uint32_t TimePickerRowPattern::GetAmPmHour(uint32_t hourOf24) const
564 {
565     if (hourOf24 == 0) {
566         return AM_PM_HOUR_12;                         // AM 12:00 means 00:00 in 24 hour style
567     }
568     if (1 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11) { // 00:00 to 11:00 is the same for any hour style
569         return hourOf24;
570     }
571     if (hourOf24 == AM_PM_HOUR_12) { // 12:00 means PM start hour
572         return AM_PM_HOUR_12;        // 12 PM
573     }                                // hour from 13 to 23
574     return hourOf24 - AM_PM_HOUR_12; // need reduce 12 to 12 hours style
575 }
576 
IsAmHour(uint32_t hourOf24) const577 bool TimePickerRowPattern::IsAmHour(uint32_t hourOf24) const
578 {
579     return (0 <= hourOf24 && hourOf24 <= AM_PM_HOUR_11); // 00:00 to 11:00 is AM hour
580 }
581 
GetAmFormatString() const582 std::string TimePickerRowPattern::GetAmFormatString() const
583 {
584     if (vecAmPm_.empty()) {
585         return "AM";
586     }
587     return vecAmPm_[0]; // first index is AM
588 }
589 
GetPmFormatString() const590 std::string TimePickerRowPattern::GetPmFormatString() const
591 {
592     if (vecAmPm_.size() < 2) { // size need to be 2 for AM and PM
593         return "PM";
594     }
595     return vecAmPm_[1]; // second index is PM
596 }
597 
GetHourFormatString(uint32_t hour) const598 std::string TimePickerRowPattern::GetHourFormatString(uint32_t hour) const
599 {
600     DateTime time;
601     time.minute = hour; // minute range [0, 59], hour range [0, 23]; hour range is in minute range.
602     if (Localization::GetInstance()->HasZeroHour()) {
603         return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
604     }
605 
606     return Localization::GetInstance()->FormatDateTime(time, "m");
607 }
608 
GetMinuteFormatString(uint32_t minute) const609 std::string TimePickerRowPattern::GetMinuteFormatString(uint32_t minute) const
610 {
611     DateTime time;
612     time.minute = minute;
613     return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
614 }
615 
AddZeroPrefix(const std::string & value) const616 std::string TimePickerRowPattern::AddZeroPrefix(const std::string& value) const
617 {
618     if (value.size() == 1 && '0' <= value[0] && value[0] <= '9') { // value is number in range [0, 9]
619         return std::string("0") + value;                           // add prefix '0'
620     }
621     return value;
622 }
623 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)624 void TimePickerRowPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
625 {
626     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
627         auto pattern = wp.Upgrade();
628         if (pattern) {
629             return pattern->OnKeyEvent(event);
630         }
631         return false;
632     };
633     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
634 
635     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
636         auto pattern = wp.Upgrade();
637         if (pattern) {
638             pattern->GetInnerFocusPaintRect(paintRect);
639         }
640     };
641     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
642 }
643 
PaintFocusState()644 void TimePickerRowPattern::PaintFocusState()
645 {
646     auto host = GetHost();
647     CHECK_NULL_VOID(host);
648 
649     RoundRect focusRect;
650     GetInnerFocusPaintRect(focusRect);
651 
652     auto focusHub = host->GetFocusHub();
653     CHECK_NULL_VOID(focusHub);
654     focusHub->PaintInnerFocusState(focusRect);
655 
656     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
657 }
658 
GetInnerFocusPaintRect(RoundRect & paintRect)659 void TimePickerRowPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
660 {
661     auto host = GetHost();
662     CHECK_NULL_VOID(host);
663     auto childSize = host->GetChildren().size();
664     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
665     CHECK_NULL_VOID(stackChild);
666     auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
667     CHECK_NULL_VOID(pickerChild);
668     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
669     auto pipeline = PipelineBase::GetCurrentContext();
670     CHECK_NULL_VOID(pipeline);
671     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
672     CHECK_NULL_VOID(pickerTheme);
673     auto frameWidth = host->GetGeometryNode()->GetFrameSize().Width();
674     auto dividerSpacing = pipeline->NormalizeToPx(pickerTheme->GetDividerSpacing());
675     auto pickerThemeWidth = dividerSpacing * 2;
676 
677     auto centerX = (frameWidth / childSize - pickerThemeWidth) / 2 +
678                    pickerChild->GetGeometryNode()->GetFrameRect().Width() * focusKeyID_ +
679                    PRESS_INTERVAL.ConvertToPx() * 2;
680     auto centerY =
681         (host->GetGeometryNode()->GetFrameSize().Height() - dividerSpacing) / 2 + PRESS_INTERVAL.ConvertToPx();
682     float piantRectWidth = (dividerSpacing - PRESS_INTERVAL.ConvertToPx()) * 2;
683     float piantRectHeight = dividerSpacing - PRESS_INTERVAL.ConvertToPx() * 2;
684     if (piantRectWidth > columnWidth) {
685         piantRectWidth = columnWidth;
686         centerX = focusKeyID_ * columnWidth;
687     }
688     paintRect.SetRect(RectF(centerX, centerY, piantRectWidth, piantRectHeight));
689     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
690         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
691     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
692         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
693     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
694         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
695     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
696         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
697 }
698 
OnKeyEvent(const KeyEvent & event)699 bool TimePickerRowPattern::OnKeyEvent(const KeyEvent& event)
700 {
701     if (event.action != KeyAction::DOWN) {
702         return false;
703     }
704     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
705         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
706         event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
707         return HandleDirectionKey(event.code);
708     }
709     return false;
710 }
711 
SetFocusDisable()712 void TimePickerRowPattern::SetFocusDisable()
713 {
714     auto host = GetHost();
715     CHECK_NULL_VOID(host);
716 
717     auto focusHub = host->GetFocusHub();
718     CHECK_NULL_VOID(focusHub);
719 
720     focusHub->SetFocusable(false);
721 }
722 
SetFocusEnable()723 void TimePickerRowPattern::SetFocusEnable()
724 {
725     auto host = GetHost();
726     CHECK_NULL_VOID(host);
727 
728     auto focusHub = host->GetFocusHub();
729     CHECK_NULL_VOID(focusHub);
730 
731     focusHub->SetFocusable(true);
732 }
733 
HandleDirectionKey(KeyCode code)734 bool TimePickerRowPattern::HandleDirectionKey(KeyCode code)
735 {
736     auto host = GetHost();
737     CHECK_NULL_RETURN(host, false);
738     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
739     auto childSize = host->GetChildren().size();
740     auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
741     auto pattern = pickerChild->GetPattern<TimePickerColumnPattern>();
742     auto currernIndex = pattern->GetCurrentIndex();
743     auto totalOptionCount = GetOptionCount(pickerChild);
744     if (totalOptionCount == 0) {
745         return false;
746     }
747     if (code == KeyCode::KEY_DPAD_UP || code == KeyCode::KEY_DPAD_DOWN) {
748         auto index = (code == KeyCode::KEY_DPAD_UP) ? -1 : 1;
749         pattern->SetCurrentIndex((totalOptionCount + currernIndex + index) % totalOptionCount);
750         pattern->FlushCurrentOptions();
751         pattern->HandleChangeCallback((code == KeyCode::KEY_DPAD_UP) ? false : true, true);
752         pattern->HandleEventCallback(true);
753         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
754         return true;
755     }
756     if (code == KeyCode::KEY_MOVE_HOME) {
757         pattern->SetCurrentIndex(1);
758         pattern->InnerHandleScroll(false, false);
759         return true;
760     }
761     if (code == KeyCode::KEY_MOVE_END) {
762         pattern->SetCurrentIndex(totalOptionCount - UNOPTION_COUNT);
763         pattern->InnerHandleScroll(true, false);
764         return true;
765     }
766     if (code == KeyCode::KEY_DPAD_LEFT) {
767         focusKeyID_ -= 1;
768         if (focusKeyID_ < 0) {
769             focusKeyID_ = 0;
770             return false;
771         }
772         PaintFocusState();
773         return true;
774     }
775     if (code == KeyCode::KEY_DPAD_RIGHT) {
776         focusKeyID_ += 1;
777         if (focusKeyID_ > static_cast<int32_t>(childSize) - 1) {
778             focusKeyID_ = static_cast<int32_t>(childSize) - 1;
779             return false;
780         }
781         PaintFocusState();
782         return true;
783     }
784     return false;
785 }
786 
OnColorConfigurationUpdate()787 void TimePickerRowPattern::OnColorConfigurationUpdate()
788 {
789     auto host = GetHost();
790     CHECK_NULL_VOID(host);
791     host->SetNeedCallChildrenUpdate(false);
792     auto context = host->GetContext();
793     CHECK_NULL_VOID(context);
794     auto pickerTheme = context->GetTheme<PickerTheme>();
795     CHECK_NULL_VOID(pickerTheme);
796     auto dialogTheme = context->GetTheme<DialogTheme>();
797     CHECK_NULL_VOID(dialogTheme);
798     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
799     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
800     auto pickerProperty = host->GetLayoutProperty<TimePickerLayoutProperty>();
801     CHECK_NULL_VOID(pickerProperty);
802     pickerProperty->UpdateColor(normalStyle.GetTextColor());
803     pickerProperty->UpdateDisappearColor(disappearStyle.GetTextColor());
804     if (isPicker_) {
805         return;
806     }
807     SetBackgroundColor(dialogTheme->GetBackgroundColor());
808     CHECK_NULL_VOID(buttonTitleNode_);
809     auto buttonTitleRenderContext = buttonTitleNode_->GetRenderContext();
810     CHECK_NULL_VOID(buttonTitleRenderContext);
811     buttonTitleRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
812     auto childText = buttonTitleNode_->GetFirstChild();
813     CHECK_NULL_VOID(childText);
814     auto textTitleNode = DynamicCast<FrameNode>(childText);
815     CHECK_NULL_VOID(textTitleNode);
816     auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
817     CHECK_NULL_VOID(textLayoutProperty);
818     textLayoutProperty->UpdateTextColor(pickerTheme->GetTitleStyle().GetTextColor());
819     CHECK_NULL_VOID(contentRowNode_);
820     auto layoutRenderContext = contentRowNode_->GetRenderContext();
821     CHECK_NULL_VOID(layoutRenderContext);
822     layoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
823     host->MarkModifyDone();
824 }
825 } // namespace OHOS::Ace::NG
826