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