1 /*
2 * Copyright (c) 2021-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/picker/picker_time_component.h"
17
18 namespace OHOS::Ace {
19
PickerTimeComponent()20 PickerTimeComponent::PickerTimeComponent()
21 {
22 vecAmPm_ = Localization::GetInstance()->GetAmPmStrings();
23 }
24
OnTitleBuilding()25 void PickerTimeComponent::OnTitleBuilding()
26 {
27 PickerBaseComponent::OnTitleBuilding();
28
29 auto titleComponent = GetTitle();
30 if (!titleComponent) {
31 LOGE("title component is null.");
32 return;
33 }
34
35 auto date = PickerDate::Current();
36 titleComponent->SetData(date.ToString(false));
37 }
38
OnColumnsBuilding()39 void PickerTimeComponent::OnColumnsBuilding()
40 {
41 HandleHourColumnBuilding();
42
43 auto minuteColumn = GetColumn(PICKER_MINUTE_COLUMN);
44 auto secondColumn = GetColumn(PICKER_SECOND_COLUMN);
45 if (!minuteColumn) {
46 LOGE("minute column is null.");
47 return;
48 }
49
50 minuteColumn->ClearOption();
51 for (uint32_t minute = 0; minute <= 59; ++minute) { // time's minute from 0 to 59
52 if (minute == selectedTime_.GetMinute()) {
53 minuteColumn->SetCurrentIndex(minuteColumn->GetOptionCount());
54 }
55 minuteColumn->AppendOption(GetMinuteFormatString(minute));
56 }
57
58 if (hasSecond_ && secondColumn) {
59 secondColumn->ClearOption();
60 for (uint32_t second = 0; second <= 59; ++second) { // time's second from 0 to 59
61 if (second == selectedTime_.GetSecond()) {
62 secondColumn->SetCurrentIndex(secondColumn->GetOptionCount());
63 }
64 secondColumn->AppendOption(GetSecondFormatString(second));
65 }
66 }
67 }
68
HandleHourColumnBuilding()69 void PickerTimeComponent::HandleHourColumnBuilding()
70 {
71 auto hourColumn = GetColumn(PICKER_HOUR_COLUMN);
72 auto amPmColumn = GetColumn(PICKER_AMPM_COLUMN);
73 if (!hourColumn) {
74 LOGE("hour column is null.");
75 return;
76 }
77
78 hourColumn->ClearOption();
79 if (hour24_) {
80 for (uint32_t hour = 0; hour <= 23; ++hour) { // time's hour from 0 to 23.
81 if (hour == selectedTime_.GetHour()) {
82 hourColumn->SetCurrentIndex(hourColumn->GetOptionCount());
83 }
84 hourColumn->AppendOption(GetHourFormatString(hour));
85 }
86 } else if (amPmColumn) {
87 amPmColumn->ClearOption();
88 amPmColumn->AppendOption(GetAmFormatString());
89 amPmColumn->AppendOption(GetPmFormatString());
90 if (IsAmHour(selectedTime_.GetHour())) {
91 amPmColumn->SetCurrentIndex(0); // AM's index
92 } else {
93 amPmColumn->SetCurrentIndex(1); // PM's index
94 }
95 auto selectedHour = GetAmPmHour(selectedTime_.GetHour());
96 for (uint32_t hour = 1; hour <= 12; ++hour) { // hour start from 1 to 12
97 if (hour == selectedHour) {
98 hourColumn->SetCurrentIndex(hourColumn->GetOptionCount());
99 }
100 hourColumn->AppendOption(GetHourFormatString(hour));
101 }
102 } else {
103 LOGE("AM PM column is null.");
104 }
105 }
106
GetSelectedObject(bool isColumnChange,const std::string & changeColumnTag,int32_t status) const107 std::string PickerTimeComponent::GetSelectedObject(bool isColumnChange,
108 const std::string& changeColumnTag, int32_t status) const
109 {
110 auto time = selectedTime_;
111 if (isColumnChange) {
112 time = GetCurrentTime();
113 }
114 return time.ToString(true, hasSecond_, status);
115 }
116
OnDataLinking(const std::string & tag,bool isAdd,uint32_t index,std::vector<std::string> & resultTags)117 void PickerTimeComponent::OnDataLinking(const std::string& tag, bool isAdd, uint32_t index,
118 std::vector<std::string>& resultTags)
119 {
120 if (tag != PICKER_HOUR_COLUMN) {
121 return;
122 }
123
124 if (hour24_) {
125 HandleHour24Change(isAdd, index, resultTags);
126 } else {
127 HandleHour12Change(isAdd, index, resultTags);
128 }
129 }
130
HandleHour24Change(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)131 void PickerTimeComponent::HandleHour24Change(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
132 {
133 if (isAdd && index == 0) {
134 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
135 return;
136 }
137 if (!isAdd && index == 23) { // hour end with 23 which is the last hour
138 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
139 return;
140 }
141 }
142
HandleHour12Change(bool isAdd,uint32_t index,std::vector<std::string> & resultTags)143 void PickerTimeComponent::HandleHour12Change(bool isAdd, uint32_t index, std::vector<std::string>& resultTags)
144 {
145 auto amPm = GetColumn(PICKER_AMPM_COLUMN);
146 if (!amPm) {
147 LOGE("AM PM column is null.");
148 return;
149 }
150
151 if (amPm->GetCurrentIndex() == 0 && isAdd && index == 11) { // hour index start from 0 to 11
152 amPm->SetCurrentIndex(1); // add to PM's index
153 resultTags.emplace_back(PICKER_AMPM_COLUMN);
154 return;
155 }
156
157 if (amPm->GetCurrentIndex() == 1 && !isAdd && index == 10) { // reduce to 11 hour (index is 10)
158 amPm->SetCurrentIndex(0); // change to AM whose index is 0
159 resultTags.emplace_back(PICKER_AMPM_COLUMN);
160 return;
161 }
162
163 if (amPm->GetCurrentIndex() == 1 && isAdd && index == 11) { // is PM (index is 1) and last hour (index is 11)
164 amPm->SetCurrentIndex(0); // change to PM (index is 0)
165 resultTags.emplace_back(PICKER_AMPM_COLUMN);
166 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
167 return;
168 }
169
170 if (amPm->GetCurrentIndex() == 0 && !isAdd && index == 10) { // reduce to 11 hour(index is 10)
171 amPm->SetCurrentIndex(1); // change to PM
172 resultTags.emplace_back(PICKER_AMPM_COLUMN);
173 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
174 return;
175 }
176 }
177
OnSelectedSaving()178 void PickerTimeComponent::OnSelectedSaving()
179 {
180 selectedTime_ = GetCurrentTime();
181 }
182
GetCurrentTime() const183 PickerTime PickerTimeComponent::GetCurrentTime() const
184 {
185 PickerTime time;
186 auto amPmColumn = GetColumn(PICKER_AMPM_COLUMN);
187 auto hourColumn = GetColumn(PICKER_HOUR_COLUMN);
188 auto minuteColumn = GetColumn(PICKER_MINUTE_COLUMN);
189 auto secondColumn = GetColumn(PICKER_SECOND_COLUMN);
190 if (!hourColumn || !minuteColumn) {
191 LOGE("hour or minute column is null.");
192 return time;
193 }
194
195 if (hour24_) {
196 time.SetHour(hourColumn->GetCurrentIndex()); // hour from 0 to 23, index from 0 to 23
197 } else if (amPmColumn) {
198 time.SetHour(GetHourFromAmPm(amPmColumn->GetCurrentIndex() == 0, hourColumn->GetCurrentIndex() + 1));
199 } else {
200 LOGE("AM PM column is null.");
201 }
202
203 time.SetMinute(minuteColumn->GetCurrentIndex()); // minute from 0 to 59, index from 0 to 59
204 if (hasSecond_ && secondColumn) {
205 time.SetSecond(secondColumn->GetCurrentIndex()); // second from 0 to 59, index from 0 to 59
206 }
207 return time;
208 }
209
OnColumnsCreating()210 void PickerTimeComponent::OnColumnsCreating()
211 {
212 RemoveColumn(PICKER_AMPM_COLUMN);
213 RemoveColumn(PICKER_HOUR_COLUMN);
214 RemoveColumn(PICKER_MINUTE_COLUMN);
215 RemoveColumn(PICKER_SECOND_COLUMN);
216
217 if (!hour24_) {
218 auto amPmColumn = AceType::MakeRefPtr<PickerColumnComponent>();
219 amPmColumn->SetColumnTag(PICKER_AMPM_COLUMN);
220 amPmColumn->SetWidthRatio(2); // date:amPm:hour:minute:second = 4:2:2:2:2
221 AppendColumn(amPmColumn);
222 }
223
224 auto hourColumn = AceType::MakeRefPtr<PickerColumnComponent>();
225 hourColumn->SetColumnTag(PICKER_HOUR_COLUMN);
226 hourColumn->SetWidthRatio(2); // date:hour:minute:second = 3:2:2:2
227 AppendColumn(hourColumn);
228
229 auto minuteColumn = AceType::MakeRefPtr<PickerColumnComponent>();
230 minuteColumn->SetColumnTag(PICKER_MINUTE_COLUMN);
231 minuteColumn->SetWidthRatio(2); // date:hour:minute:second = 3:2:2:2
232 AppendColumn(minuteColumn);
233
234 if (hasSecond_) {
235 auto secondColumn = AceType::MakeRefPtr<PickerColumnComponent>();
236 secondColumn->SetColumnTag(PICKER_SECOND_COLUMN);
237 secondColumn->SetWidthRatio(2); // date:hour:minute:second = 3:2:2:2
238 AppendColumn(secondColumn);
239 auto theme = GetTheme();
240 if (!theme) {
241 return;
242 }
243 hourColumn->SetHasSplitter(theme->HasTimeSplitter());
244 minuteColumn->SetHasSplitter(theme->HasTimeSplitter());
245 }
246 }
247
GetAmFormatString() const248 std::string PickerTimeComponent::GetAmFormatString() const
249 {
250 if (vecAmPm_.empty()) {
251 return "AM";
252 }
253 return vecAmPm_[0]; // first index is AM
254 }
255
GetPmFormatString() const256 std::string PickerTimeComponent::GetPmFormatString() const
257 {
258 if (vecAmPm_.size() < 2) { // size need to be 2 for AM and PM
259 return "PM";
260 }
261 return vecAmPm_[1]; // second index is PM
262 }
263
IsAmHour(uint32_t hourOf24) const264 bool PickerTimeComponent::IsAmHour(uint32_t hourOf24) const
265 {
266 return (0 <= hourOf24 && hourOf24 <= 11); // 00:00 to 11:00 is AM hour
267 }
268
GetAmPmHour(uint32_t hourOf24) const269 uint32_t PickerTimeComponent::GetAmPmHour(uint32_t hourOf24) const
270 {
271 if (hourOf24 == 0) {
272 return 12; // AM 12:00 means 00:00 in 24 hour style
273 } else if (1 <= hourOf24 && hourOf24 <= 11) { // 00:00 to 11:00 is the same for any hour style
274 return hourOf24;
275 } else if (hourOf24 == 12) { // 12:00 means PM start hour
276 return 12; // 12 PM
277 } else { // hour from 13 to 23
278 return hourOf24 - 12; // need reduce 12 to 12 hours style
279 }
280 }
281
GetHourFromAmPm(bool isAm,uint32_t amPmhour) const282 uint32_t PickerTimeComponent::GetHourFromAmPm(bool isAm, uint32_t amPmhour) const
283 {
284 if (isAm) {
285 if (amPmhour == 12) { // AM 12:00 means 00:00
286 return 0;
287 }
288 return amPmhour;
289 }
290
291 if (amPmhour == 12) { // PM 12 means 12:00
292 return 12;
293 }
294
295 return amPmhour + 12; // need add 12 hour to 24 hours style
296 }
297
GetHourFormatString(uint32_t hour) const298 std::string PickerTimeComponent::GetHourFormatString(uint32_t hour) const
299 {
300 DateTime time;
301 time.minute = hour; // minute range [0, 59], hour range [0, 23]; hour range is in minute range.
302 if (Localization::GetInstance()->HasZeroHour()) {
303 return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
304 }
305
306 return Localization::GetInstance()->FormatDateTime(time, "m");
307 }
308
GetMinuteFormatString(uint32_t minute) const309 std::string PickerTimeComponent::GetMinuteFormatString(uint32_t minute) const
310 {
311 DateTime time;
312 time.minute = minute;
313 return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "m"));
314 }
315
GetSecondFormatString(uint32_t second) const316 std::string PickerTimeComponent::GetSecondFormatString(uint32_t second) const
317 {
318 DateTime time;
319 time.second = second;
320 return AddZeroPrefix(Localization::GetInstance()->FormatDateTime(time, "s"));
321 }
322
AddZeroPrefix(const std::string & value) const323 std::string PickerTimeComponent::AddZeroPrefix(const std::string& value) const
324 {
325 if (value.size() == 1 && '0' <= value[0] && value[0] <= '9') { // value is number in range [0, 9]
326 return std::string("0") + value; // add prefix '0'
327 }
328 return value;
329 }
330
331 } // namespace OHOS::Ace
332