Add update of GenlistItem fields when text and description are changed
[profile/mobile/apps/native/accessibility-setting.git] / src / ScreenReaderSettingsPage.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 "ScreenReaderSettingsPage.hpp"
18
19 #include "Box.hpp"
20 #include "Button.hpp"
21 #include "Genlist.hpp"
22 #include "Layout.hpp"
23 #include "Singleton.hpp"
24 #include "Slider.hpp"
25 #include "TextToSpeech.hpp"
26 #include "VConf.hpp"
27 #include "setting-accessibility.h"
28 #include "utils.hpp"
29
30 #include <app.h>
31 #include <efl_extension.h>
32 #include <vconf-internal-keys.h>
33 #include <vconf.h>
34
35 namespace
36 {
37         struct VConfCheckData
38         {
39                 std::string label;
40                 std::string vconf_key;
41                 bool state = false;
42         };
43
44         std::vector<VConfCheckData> vConfCheckData = {{"IDS_ST_HEADER_TIME", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_TIME},
45                 {"IDS_ST_BODY_DATE", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_DATE},
46                 {"IDS_ST_BODY_BATTERY", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_BATTERY},
47                 {"IDS_ST_BODY_SIGNAL_STRENGTH", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_SIGNAL_STRENGHT},
48                 {"IDS_ST_BODY_BLUETOOTH", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_BLUETOOTH},
49                 {"IDS_ST_BODY_MISSED_EVENTS", VCONFKEY_SETAPPL_ACCESSIBILITY_TTS_INDICATOR_INFORMATION_MISSED_EVENTS}};
50
51         static const size_t POPUP_CONTENT_BASE_SIZE = 120;
52 } // namespace
53
54 ScreenReaderSettingsPage::ScreenReaderSettingsPage()
55         : context_(Singleton<AppContext>::instance())
56 {
57         auto genlist = Widget::make<Genlist>(context_.navContext_.getNaviframe());
58         genlist->setMode(ELM_LIST_COMPRESS);
59         genlist->setStyle("dialogue");
60         genlist->clear(); // TODO check if necessary
61
62         DEBUG("Creating items");
63
64         auto percentage = calculateSpeedPercentage();
65         speechRateItem_ = genlist->appendItem({"type1", "IDS_ST_BODY_SPEECH_RATE", percentage, [this](auto item) { this->createSpeechRatePopup(); }});
66
67         Singleton<TextToSpeech>::instance().addSpeedChangedCb([item = speechRateItem_](auto val) {
68                 DEBUG("Speed changed to (%d)", static_cast<int>(val));
69                 item->setDescription(std::to_string(val));
70         });
71
72         auto item = genlist->appendItem({"multiline",
73                 "IDS_ACCS_OPT_KEYBOARD_FEEDBACK_TTS",
74                 "IDS_ACCS_OPT_ALWAYS_READ_OUT_KEYBOARD_INPUT_TTS",
75                 [](auto item) {
76                         Singleton<VConfInterface>::instance().set(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_KEYBOARD_FEEDBACK, item->getState());
77                 },
78                 GenlistItem::WidgetType::toggle});
79         item->setState(Singleton<VConfInterface>::instance().get(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_KEYBOARD_FEEDBACK, false));
80
81         item = genlist->appendItem({"type1",
82                 "IDS_ACCS_MBODY_READ_OUT_USAGE_HINTS_ABB",
83                 {},
84                 [](auto item) {
85                         Singleton<VConfInterface>::instance().set(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_DESCRIPTION, item->getState());
86                 },
87                 GenlistItem::WidgetType::toggle});
88         item->setState(Singleton<VConfInterface>::instance().get(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_DESCRIPTION, false));
89
90         item = genlist->appendItem({"type1",
91                 "IDS_ACCS_MBODY_VIBRATION_FEEDBACK",
92                 {},
93                 [](auto item) {
94                         Singleton<VConfInterface>::instance().set(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_HAPTIC, item->getState());
95                 },
96                 GenlistItem::WidgetType::toggle});
97         item->setState(Singleton<VConfInterface>::instance().get(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_HAPTIC, false));
98
99         item = genlist->appendItem({"type1",
100                 "IDS_ACCS_MBODY_SOUND_FEEDBACK",
101                 {},
102                 [](auto item) {
103                         Singleton<VConfInterface>::instance().set(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_SOUND_FEEDBACK, item->getState());
104                 },
105                 GenlistItem::WidgetType::toggle});
106         item->setState(Singleton<VConfInterface>::instance().get(VCONFKEY_SETAPPL_ACCESSIBILITY_SCREEN_READER_SOUND_FEEDBACK, false));
107
108         genlist->appendItem({"type1", "IDS_ACCS_TMBODY_STATUS_BAR_INFORMATION", {}, [this](auto item) { this->mouseUpGendialListCb(); }});
109
110         genlist->appendItem({"multiline",
111                 {},
112                 "IDS_ACCS_SBODY_SELECT_WHICH_INFORMATION_FROM_INDICATORS_SHOWN_ON_THE_STATUS_BAR_WILL_BE_READ_OUT_WHEN_YOU_TRIPLE_"
113                 "TAP_THE_SCREEN_WITH_TWO_FINGERS_MSG",
114                 [this](auto item) {}});
115
116         context_.navContext_.getNaviframe()->pushBack("IDS_ST_OPT_SETTINGS", genlist, [this]() {
117                 Singleton<TextToSpeech>::instance().clearSpeedChangedCallbacks();
118         });
119 }
120
121 void ScreenReaderSettingsPage::mouseUpGendialListCb()
122 {
123         auto window = this->context_.navContext_.getWindow();
124
125         this->popup_ = Widget::make<Popup>(window, "IDS_ACCS_TMBODY_STATUS_BAR_INFORMATION");
126         this->popup_->setAlignment(ELM_NOTIFY_ALIGN_FILL, 1.0);
127
128         auto removeCb = [p = this->popup_, window]() { window->removeChild(p); };
129         this->popup_->setEextEventCallback(EEXT_CALLBACK_BACK, removeCb);
130
131         auto box = Widget::make<Box>(this->popup_);
132
133         auto genlist = Widget::make<Genlist>(box);
134         genlist->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
135         genlist->setAlignHint(EVAS_HINT_FILL, EVAS_HINT_FILL);
136
137         for (auto i = 0u; i < vConfCheckData.size(); ++i) {
138                 auto screenreaderCheckbox = genlist->appendItem({"type1",
139                         vConfCheckData[i].label,
140                         {},
141                         [i](auto item) {
142                                 vConfCheckData[i].state = item->getState();
143                         },
144                         GenlistItem::WidgetType::toggle});
145                 vConfCheckData[i].state = Singleton<VConfInterface>::instance().get(vConfCheckData[i].vconf_key, vConfCheckData[i].state);
146                 screenreaderCheckbox->setState(vConfCheckData[i].state);
147         }
148
149         genlist->blockScrolling(Elm_Scroller_Movement_Block(ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL | ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL));
150         genlist->setScrollbarsVisibility(ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
151
152         box->packEnd(genlist);
153
154         box->setMinSizeHint(-1, ELM_SCALE_SIZE(POPUP_CONTENT_BASE_SIZE) * vConfCheckData.size());
155         box->setMaxSizeHint(-1, ELM_SCALE_SIZE(POPUP_CONTENT_BASE_SIZE) * vConfCheckData.size());
156         this->popup_->setContent(box);
157
158         auto btnCancel = Widget::make<Button>(this->popup_, removeCb, "IDS_MSG_ACBUTTON_CANCEL_ABB", "popup");
159         this->popup_->setPartContent("button1", btnCancel);
160
161         auto onDone = [removeCb]() {
162                 removeCb();
163
164                 for (auto vConfData : vConfCheckData)
165                         Singleton<VConfInterface>::instance().set(vConfData.vconf_key, vConfData.state);
166         };
167
168         auto btnDone = Widget::make<Button>(this->popup_, onDone, "IDS_MSG_ACBUTTON_DONE_ABB", "popup");
169         this->popup_->setPartContent("button2", btnDone);
170 }
171
172 void ScreenReaderSettingsPage::createSpeechRatePopup()
173 {
174         auto window = context_.navContext_.getWindow();
175
176         popup_ = Widget::make<Popup>(window, "IDS_ST_BODY_SPEECH_RATE");
177         popup_->setAlignment(ELM_NOTIFY_ALIGN_FILL, 1.0);
178
179         auto removeCb = [p = popup_, window]() { window->removeChild(p); };
180         popup_->setEextEventCallback(EEXT_CALLBACK_BACK, removeCb);
181
182         auto layout = Widget::make<Layout>(popup_);
183         layout->setFile(EDJDIR "/screen-reader-settings-popup.edj", "popup_text_slider_view_layout");
184         layout->setPartText("elm.text.description", "IDS_SCR_POP_DRAG_THE_SLIDER_TO_SET_THE_SPEECH_RATE");
185         layout->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
186         popup_->setContent(layout);
187
188         auto slider = Widget::make<Slider>(layout);
189         slider->showIndicator(true);
190         slider->setWeightHint(EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
191         slider->setAlignHint(EVAS_HINT_FILL, EVAS_HINT_FILL);
192         slider->setIndicatorFormat("%1.0f");
193         slider->setRange(1, 15);
194
195         auto speed = Singleton<TextToSpeech>::instance().getSpeed();
196
197         slider->setStep(2);
198         slider->setValue(speed);
199         layout->setPartContent("slider", slider);
200
201         auto cancelBtn = Widget::make<Button>(popup_, removeCb, "IDS_ST_BUTTON_CANCEL_ABB", "bottom");
202         popup_->setPartContent("button1", cancelBtn);
203
204         auto doneBtn = Widget::make<Button>(popup_,
205                 [p = popup_, window, slider, this]() {
206                         auto val = static_cast<size_t>(slider->getValue());
207                         Singleton<TextToSpeech>::instance().setSpeed(val);
208                         window->removeChild(p);
209                 },
210                 "IDS_ST_SK3_DONE",
211                 "bottom");
212         popup_->setPartContent("button2", doneBtn);
213
214         // TODO: add wrapper to the below function
215         evas_object_event_callback_add(popup_->getObject(), EVAS_CALLBACK_DEL, onPopupDel, this);
216 }
217
218 std::string ScreenReaderSettingsPage::calculateSpeedPercentage()
219 {
220         auto speed = Singleton<TextToSpeech>::instance().getSpeed();
221         auto speedRange = Singleton<TextToSpeech>::instance().getSpeedRange();
222
223         auto denominator = speedRange.max - speedRange.min;
224         auto speedPercent = 0.0;
225         if (denominator != 0)
226                 speedPercent = (static_cast<double>(speed - speedRange.min) / denominator) * 100;
227
228         DEBUG("TTS rate is %.0f", speedPercent);
229         return std::to_string(std::lround(speedPercent));
230 }
231
232 void ScreenReaderSettingsPage::onPopupDel(void *data, Evas *e, Evas_Object *obj, void *event_info)
233 {
234         auto self = static_cast<ScreenReaderSettingsPage *>(data);
235         auto percentage = self->calculateSpeedPercentage();
236         self->speechRateItem_->setDescription(percentage);
237 }