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_datetime_component.h"
17
18 #include "base/i18n/localization.h"
19
20 namespace OHOS::Ace {
21
PickerDateTimeComponent()22 PickerDateTimeComponent::PickerDateTimeComponent() {}
23
OnTitleBuilding()24 void PickerDateTimeComponent::OnTitleBuilding()
25 {
26 auto theme = GetTheme();
27 if (!theme) {
28 LOGE("theme is null.");
29 return;
30 }
31 SetHasTitle(theme->GetShowButtons());
32 SetHasButtons(theme->GetShowButtons());
33 SetHasTriangle(true); // triangle only for datetime picker.
34
35 auto titleComponent = GetTitle();
36 if (!titleComponent) {
37 LOGE("title component is null.");
38 return;
39 }
40 titleComponent->SetData(currentDate_.ToString(false));
41 }
42
OnColumnsBuilding()43 void PickerDateTimeComponent::OnColumnsBuilding()
44 {
45 PickerTimeComponent::OnColumnsBuilding();
46 FillSolarLunarDays(lunar_, selectedDate_);
47 InitDatePicker();
48 }
49
OnSelectedSaving()50 void PickerDateTimeComponent::OnSelectedSaving()
51 {
52 PickerTimeComponent::OnSelectedSaving();
53 selectedDate_ = currentDate_;
54 }
55
GetSelectedObject(bool isColumnChange,const std::string & changeColumnTag,int32_t status) const56 std::string PickerDateTimeComponent::GetSelectedObject(bool isColumnChange,
57 const std::string& changeColumnTag, int32_t status) const
58 {
59 if (isColumnChange) {
60 LOGE("datetime picker not support column change event.");
61 return "{}";
62 }
63
64 auto date = selectedDate_;
65 // W3C's month is between 0 to 11, need to reduce one.
66 date.SetMonth(date.GetMonth() - 1);
67 PickerDateTime dateTime(date, GetSelectedTime());
68 return dateTime.ToString(true, status);
69 }
70
OnLunarCallback(bool checked,std::vector<std::string> & resultTags)71 void PickerDateTimeComponent::OnLunarCallback(bool checked, std::vector<std::string>& resultTags)
72 {
73 FillSolarLunarDays(checked, currentDate_);
74 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
75 }
76
OnTriangleCallback(bool value)77 void PickerDateTimeComponent::OnTriangleCallback(bool value)
78 {
79 if (value) {
80 HideDatePicker();
81 } else {
82 ShowDatePicker();
83 }
84 }
85
InitDatePicker()86 void PickerDateTimeComponent::InitDatePicker()
87 {
88 if (datePicker_) {
89 return; // already init.
90 }
91 datePicker_ = AceType::MakeRefPtr<PickerDateComponent>();
92 datePicker_->SetSubsidiary(true);
93 datePicker_->SetHasLunar(false);
94 datePicker_->SetIsDialog(true);
95 datePicker_->SetTextDirection(GetTextDirection());
96 datePicker_->SetTheme(GetTheme());
97 datePicker_->SetColumnHeight(GetColumnHeight());
98 datePicker_->SetOnDateChange([weak = WeakClaim(this)] (const PickerDate& date) {
99 auto refPtr = weak.Upgrade();
100 if (!refPtr) {
101 return;
102 }
103 refPtr->OnSubsidiaryChange(date);
104 });
105 auto controller = AceType::MakeRefPtr<PickerAnimationController>();
106 controller->SetOutStopCallback([weak = AceType::WeakClaim(AceType::RawPtr(datePicker_))] {
107 auto refPtr = weak.Upgrade();
108 if (!refPtr) {
109 return;
110 }
111 refPtr->HideDialog();
112 });
113 SetAnimationController(controller);
114 datePicker_->SetAnimationController(controller);
115 }
116
OnSubsidiaryChange(const PickerDate & date)117 void PickerDateTimeComponent::OnSubsidiaryChange(const PickerDate& date)
118 {
119 auto days = date.ToDays();
120 days--;
121 currentDate_.FromDays(days);
122
123 auto monthDay = GetColumn(PICKER_MONTHDAY_COLUMN);
124 if (!monthDay) {
125 return;
126 }
127
128 monthDay->HandleChangeCallback(true, false);
129 }
130
ShowDatePicker()131 void PickerDateTimeComponent::ShowDatePicker()
132 {
133 InitDatePicker();
134 #if defined(PREVIEW)
135 datePicker_->SetPickerBaseId(GetPickerBaseId());
136 #endif
137 datePicker_->SetShowLunar(lunar_);
138 datePicker_->SetSelectedDate(currentDate_);
139 datePicker_->SetMasterHasLunar(GetHasLunar());
140 datePicker_->ShowDialog(GetStack(), false);
141 }
142
HideDatePicker()143 void PickerDateTimeComponent::HideDatePicker()
144 {
145 InitDatePicker();
146 auto controller = GetAnimationController();
147 if (!controller) {
148 LOGE("controller is null.");
149 return;
150 }
151
152 controller->Play(false);
153 }
154
OnColumnsCreating()155 void PickerDateTimeComponent::OnColumnsCreating()
156 {
157 RemoveColumn(PICKER_MONTHDAY_COLUMN);
158 auto monthDay = AceType::MakeRefPtr<PickerColumnComponent>();
159 monthDay->SetColumnTag(PICKER_MONTHDAY_COLUMN);
160 if (GetHour24()) {
161 monthDay->SetWidthRatio(3); // date:hour:minute:second = 3:2:2:2
162 } else {
163 monthDay->SetWidthRatio(4); // date:amPm:hour:minute:second = 4:2:2:2:2
164 }
165 AppendColumn(monthDay);
166
167 PickerTimeComponent::OnColumnsCreating();
168 }
169
GetMonthDayFormatString(bool lunar,uint32_t days) const170 std::string PickerDateTimeComponent::GetMonthDayFormatString(bool lunar, uint32_t days) const
171 {
172 PickerDate outDate;
173 outDate.FromDays(days);
174 auto nowadays = PickerDate::Current().ToDays();
175 if (days == nowadays) {
176 return Localization::GetInstance()->GetRelativeDateTime(0.0);
177 }
178 if (!lunar) {
179 DateTime dateTime;
180 dateTime.year = outDate.GetYear();
181 dateTime.month = outDate.GetMonth() - 1; // W3C's month start from 0 to 11
182 dateTime.day = outDate.GetDay();
183 return Localization::GetInstance()->FormatDateTime(dateTime, "MMMd");
184 }
185 Date date;
186 date.year = outDate.GetYear();
187 date.month = outDate.GetMonth();
188 date.day = outDate.GetDay();
189 auto lunarDate = Localization::GetInstance()->GetLunarDate(date);
190 return Localization::GetInstance()->GetLunarMonth(lunarDate.month, lunarDate.isLeapMonth) +
191 Localization::GetInstance()->GetLunarDay(lunarDate.day);
192 }
193
FillSolarLunarDays(bool lunar,const PickerDate & currentDate)194 void PickerDateTimeComponent::FillSolarLunarDays(bool lunar, const PickerDate& currentDate)
195 {
196 auto monthDay = GetColumn(PICKER_MONTHDAY_COLUMN);
197 if (!monthDay) {
198 return;
199 }
200 monthDay->ClearOption();
201 monthDay->SetCurrentIndex(3); // total option is fixed 7. center index is 3 which is current.
202 uint32_t centerDays = currentDate.ToDays();
203 uint32_t startDays = centerDays - 3; // start day 3 days before center day.
204 uint32_t endDays = centerDays + 3; // end day 3 days after center day.
205 for (uint32_t days = startDays; days <= endDays; ++days) {
206 monthDay->AppendOption(GetMonthDayFormatString(lunar, days));
207 }
208 lunar_ = lunar;
209 currentDate_ = currentDate;
210 }
211
OnDataLinking(const std::string & tag,bool isAdd,uint32_t index,std::vector<std::string> & resultTags)212 void PickerDateTimeComponent::OnDataLinking(const std::string& tag, bool isAdd, uint32_t index,
213 std::vector<std::string>& resultTags)
214 {
215 PickerTimeComponent::OnDataLinking(tag, isAdd, index, resultTags);
216 if (tag == PICKER_MONTHDAY_COLUMN) {
217 // linked by month day column itself.
218 auto days = currentDate_.ToDays();
219 days = (isAdd ? days + 1 : days - 1); // add one day or reduce one day.
220 PickerDate date;
221 date.FromDays(days);
222 FillSolarLunarDays(lunar_, date);
223 resultTags.emplace_back(PICKER_MONTHDAY_COLUMN);
224 return;
225 }
226 auto it = std::find(resultTags.begin(), resultTags.end(), PICKER_MONTHDAY_COLUMN);
227 if (it != resultTags.end()) {
228 // linked by other column
229 auto days = currentDate_.ToDays();
230 days = (isAdd ? days + 1 : days - 1);
231 PickerDate date;
232 date.FromDays(days);
233 FillSolarLunarDays(lunar_, date);
234 }
235 }
236
237 } // namespace OHOS::Ace
238