Add update of GenlistItem fields when text and description are changed
[profile/mobile/apps/native/accessibility-setting.git] / src / SetValuePage.cpp
1 /*
2  * Copyright 2018 Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *  http://www.apache.org/licenses/LICENSE-2.0
9
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "SetValuePage.hpp"
18
19 #include "AccessibilitySettingLog.hpp"
20 #include "Button.hpp"
21 #include "Genlist.hpp"
22 #include "Label.hpp"
23 #include "Singleton.hpp"
24 #include "setting-accessibility.h"
25
26 #include <app.h>
27 #include <sstream>
28
29 #define EDJ_SET_VALUE "edje/accessibility-settings-set-value.edj"
30
31 SetValuePage::SetValuePage(ValueEditorType type, TranslatedString title, NaviframeItem targetItem)
32         : context_(Singleton<AppContext>::instance()), naviframeItem_(targetItem)
33 {
34         auto layoutGroup = std::string{};
35         RETURN_IF(title.empty(), "Title parameter is NULL");
36
37         switch (type) {
38         case ValueEditorType::NUMERIC:
39                 layoutGroup = "set-value-numeric";
40                 break;
41         case ValueEditorType::NUMERIC_SWITCH:
42                 layoutGroup = "set-value-numeric-switch";
43                 break;
44         case ValueEditorType::RADIOS:
45         case ValueEditorType::SWITCHES:
46                 layoutGroup = "set-value-switches";
47                 break;
48         case ValueEditorType::LIST_SWITCH:
49                 layoutGroup = "set-value-list-switch";
50                 break;
51         default:
52                 layoutGroup = "set-value-numeric";
53                 ERROR("Unrecognized layout type");
54         }
55         auto naviframe = context_.navContext_.getNaviframe();
56         layout_ = createLayout(naviframe, layoutGroup);
57
58         switch (type) {
59         case ValueEditorType::NUMERIC:
60                 createScroller();
61                 break;
62         case ValueEditorType::NUMERIC_SWITCH:
63                 createScroller();
64                 check_ = Widget::make<Check>(layout_, false, "on&off", [this]() { checkStateChangedCb(); });
65                 layout_->setPartContent("set-value-switch", check_);
66                 check_->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
67                 break;
68         case ValueEditorType::RADIOS:
69                 genlist_ = createGenlist(layout_, {});
70                 break;
71         case ValueEditorType::SWITCHES:
72                 genlist_ = createGenlist(layout_, {});
73                 break;
74         case ValueEditorType::LIST_SWITCH:
75                 check_ = Widget::make<Check>(layout_, false, "on&off", [this]() { checkStateChangedCb(); });
76                 layout_->setPartContent("set-value-switch", check_);
77                 check_->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
78                 genlist_ = createGenlist(layout_, "IDS_ACCS_UNIVERSAL_SWITCH_SETTINGS_GROUP_FEEDBACK_OPTIONS");
79                 break;
80         default:
81                 ERROR("Wrong value type");
82         }
83
84         auto prevBtn = Widget::make<Button>(
85                 naviframe, [naviframe]() { naviframe->popBack(); }, std::string{}, Button::BACK_BUTTON_ARROW_STYLE);
86
87         naviframe->pushBack(std::move(title),
88                 layout_,
89                 [this]() {
90                         context_.usScanningProperties.getScanningProperty(Property::FEEDBACK_VOICE)->unregisterOnValueChangeCallback();
91                         context_.usScanningProperties.getScanningProperty(Property::FEEDBACK_SOUND)->unregisterOnValueChangeCallback();
92
93                         if (changeValueCb_) {
94                                 auto pageNum = scroller_->getCurrentVerticalPage();
95                                 changeValueCb_(static_cast<double>(pageNum) * step_ + minVal_);
96                         }
97
98                         if (!options_data.empty()) {
99                                 for (auto it : options_data)
100                                         free(it);
101                                 options_data.clear();
102                         }
103                 },
104                 prevBtn);
105 }
106
107 void SetValuePage::setDescription(const TranslatedString &description)
108 {
109         layout_->setPartText("set-value-desc", description);
110 }
111
112 void SetValuePage::setRange(double min, double max, double step)
113 {
114         RETURN_IF(min >= max, "Invalid min/max arguments");
115         RETURN_IF(step <= 0.0, "Invalid step value");
116
117         minVal_ = min;
118         maxVal_ = max;
119         step_ = step;
120
121         box_->packEnd(Widget::make<Label>(box_, ""));
122         box_->packEnd(Widget::make<Label>(box_, ""));
123
124         for (auto i = min; i < max + step / 2; i += step) {
125                 std::ostringstream out;
126                 out << "<font=BreezeSans:style=normal font_size=50 color=#7f7f7f>";
127                 if (step < 1.0)
128                         out.precision(1);
129                 else
130                         out.precision(0);
131                 out << std::fixed << i << "</font/>";
132
133                 box_->packEnd(Widget::make<Label>(box_, out.str().c_str()));
134         }
135
136         box_->packEnd(Widget::make<Label>(box_, ""));
137         box_->packEnd(Widget::make<Label>(box_, ""));
138
139         std::ostringstream out;
140         if (step_ < 1.0)
141                 out.precision(1);
142         else
143                 out.precision(0);
144
145         out << std::fixed << "Accepted range: " << min << " to " << max; // TODO translation
146
147         layout_->setPartText("set-value-range", out.str());
148 }
149
150 void SetValuePage::setValue(double value, const std::string &units)
151 {
152         RETURN_IF(value < minVal_, "Invalid value");
153         RETURN_IF(value > maxVal_, "Invalid value");
154
155         units_ = units;
156         scroller_->showVerticalPage((value - minVal_) / step_);
157
158         displayValue(value);
159 }
160
161 void SetValuePage::setSwitch(bool state)
162 {
163         check_->setState(state);
164
165         if (state)
166                 layout_->setPartText("set-value-switch-label", "IDS_ACCS_UNIVERSAL_SWITCH_SETTINGS_ON");
167         else
168                 layout_->setPartText("set-value-switch-label", "IDS_ACCS_UNIVERSAL_SWITCH_SETTINGS_OFF");
169 }
170
171 void SetValuePage::addRadioItem(const std::string &caption, int id, bool selected)
172 {
173         auto item = genlist_->appendItem({"type1",
174                 caption,
175                 {},
176                 [this](auto item) { this->callRadioItemChangeCbAndPopNaviframe(item); },
177                 GenlistItem::WidgetType::radio});
178
179         item->setState(selected);
180         item->setId(id);
181 }
182
183 GenlistItem *SetValuePage::addRadioListItem(const std::string &main_text, const std::string &sub_text, int option_id)
184 {
185         auto opt_item = new OptionsItem;
186         opt_item->self = this;
187         opt_item->option_id = option_id;
188         options_data.push_back(opt_item);
189
190         auto item = genlist_->appendItem({"type1", main_text, sub_text, [=](auto item) {
191                                                                                   if (opt_item->self->requestListItemOptionsCb_)
192                                                                                           opt_item->self->requestListItemOptionsCb_(opt_item->option_id);
193                                                                           }});
194
195         if (check_->getState())
196                 item->enable();
197         else
198                 item->disable();
199
200         return item;
201 }
202
203 void SetValuePage::addValueChangedCb(ChangeValueCb cb)
204 {
205         changeValueCb_ = std::move(cb);
206 }
207
208 void SetValuePage::addSwitchChangedCb(ChangeSwitchCb cb)
209 {
210         changeSwitchCb_ = std::move(cb);
211 }
212
213 void SetValuePage::addRadioItemChangedCb(ChangeRadioItemCb cb)
214 {
215         changeRadioItemCb_ = std::move(cb);
216 }
217
218 void SetValuePage::addListItemOptionsRequestCb(RequestListItemOptionsCb cb)
219 {
220         requestListItemOptionsCb_ = std::move(cb);
221 }
222
223 void SetValuePage::setCheckState(bool state)
224 {
225         check_->setState(state);
226 }
227
228 void SetValuePage::callRadioItemChangeCbAndPopNaviframe(GenlistItem *item)
229 {
230         if (changeRadioItemCb_)
231                 changeRadioItemCb_(item->getId());
232         context_.navContext_.getNaviframe()->popBack(naviframeItem_);
233 }
234
235 Genlist *SetValuePage::createGenlist(Widget *parent, TranslatedString title)
236 {
237         RETURN_DEFAULT_IF(!parent, "Input parameter is nullptr");
238
239         auto genlist = Widget::make<Genlist>(parent);
240         genlist->setMode(ELM_LIST_COMPRESS);
241         genlist->setStyle("dialogue");
242
243         if (!title.empty())
244                 genlist->appendItem({"group_index", std::move(title)});
245
246         parent->setPartContent("set-value-list", genlist);
247
248         return genlist;
249 }
250
251 void SetValuePage::createScroller()
252 {
253         scroller_ = Widget::make<Scroller>(layout_);
254         scroller_->setScrollbarsVisibility(ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
255         scroller_->setMinimumSizeLimit(EINA_FALSE, EINA_FALSE);
256         scroller_->blockScrolling(ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL);
257         scroller_->setRelativeSize(1.0, 0.2);
258         scroller_->setPageScrollLimit(1, 1);
259         layout_->setPartContent("set-value-selector", scroller_);
260         box_ = Widget::make<Box>(scroller_);
261         box_->setHomogeneousDimensions();
262         box_->setAlignHint(0.0, 0.0);
263         scroller_->setContent(box_);
264         scroller_->setEvasSmartCallback("scroll,page,changed", [this]() {
265                 auto pageNum = scroller_->getCurrentVerticalPage();
266                 displayValue(static_cast<double>(pageNum) * step_ + minVal_);
267         });
268 }
269
270 Layout *SetValuePage::createLayout(Widget *parent, const std::string &layoutGroup)
271 {
272         auto resPath = std::string{app_get_resource_path()};
273         auto edjPath = resPath + "edje/accessibility-settings-set-value.edj";
274
275         auto layout = Widget::make<Layout>(parent);
276         layout->setFile(edjPath, layoutGroup);
277         layout->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
278
279         return layout;
280 }
281
282 void SetValuePage::displayValue(double value)
283 {
284         std::ostringstream out;
285         if (step_ < 1.0)
286                 out.precision(1);
287         else
288                 out.precision(0);
289
290         out << std::fixed << value << " " << units_; // TODO translation
291
292         layout_->setPartText("set-value-value", out.str());
293 }
294
295 void SetValuePage::checkStateChangedCb()
296 {
297         auto state = check_->getState();
298
299         if (state)
300                 layout_->setPartText("set-value-switch-label", "IDS_ACCS_UNIVERSAL_SWITCH_SETTINGS_ON");
301         else
302                 layout_->setPartText("set-value-switch-label", "IDS_ACCS_UNIVERSAL_SWITCH_SETTINGS_OFF");
303
304         if (genlist_) {
305                 Elm_Object_Item *item = elm_genlist_first_item_get(genlist_->getObject());
306                 do {
307                         elm_object_item_disabled_set(item, !state);
308                         item = elm_genlist_item_next_get(item);
309                 } while (item != NULL);
310         }
311
312         if (changeSwitchCb_)
313                 changeSwitchCb_(state);
314 }