Add channel next/prev event
[profile/tv/apps/native/air_livetv.git] / src / view_channelinfo.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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 <Elementary.h>
18 #include <viewmgr.h>
19 #include <layoutmgr.h>
20 #include <inputmgr.h>
21 #include <app_debug.h>
22
23 #include "define.h"
24 #include "tv.h"
25 #include "view_channelinfo.h"
26 #include "layout_channelinfo.h"
27 #include "layout_channelinfo_list.h"
28 #include "layout_channelinfo_search.h"
29
30 #define HIDE_DUR 10.0
31 #define BUF_MAX 128
32 #define STATUS_BOX_PADDING 10
33
34 enum _update_op {
35         START_HIDE_TIMER,
36         STOP_HIDE_TIMER
37 };
38
39 struct _priv {
40         Evas_Object *base;
41         Ecore_Timer *hide_timer;
42         const char *current_layout;
43
44         layoutmgr *lmgr;
45 };
46
47 static int _get_program_time(char *buf, int buf_len, time_t start_time,
48                 time_t end_time)
49 {
50         struct tm tm;
51         int r;
52
53         if (start_time >= end_time) {
54                 _ERR("invalid time");
55                 return -1;
56         }
57
58         localtime_r(&start_time, &tm);
59         r = strftime(buf, buf_len, "%I:%M %P -", &tm);
60         if (r <= 0)
61                 return -1;
62
63         localtime_r(&end_time, &tm);
64         r = strftime(buf + r, buf_len - r, " %I:%M %P", &tm);
65         if (r <= 0)
66                 return -1;
67
68         return 0;
69 }
70
71 static Eina_Bool _hide_timer(void *data)
72 {
73         struct _priv *priv;
74
75         if (!data)
76                 return ECORE_CALLBACK_CANCEL;
77
78         priv = data;
79
80         priv->hide_timer = NULL;
81
82         viewmgr_hide_view(VIEW_CHANNELINFO);
83
84         return ECORE_CALLBACK_CANCEL;
85 }
86
87 static void _start_hide_timer(struct _priv *priv)
88 {
89         if (priv->hide_timer)
90                 ecore_timer_reset(priv->hide_timer);
91         else
92                 priv->hide_timer = ecore_timer_add(HIDE_DUR, _hide_timer, priv);
93 }
94
95 static void _stop_hide_timer(struct _priv *priv)
96 {
97         if (priv->hide_timer) {
98                 ecore_timer_del(priv->hide_timer);
99                 priv->hide_timer = NULL;
100         }
101 }
102
103 static void _add_icon(Evas_Object *box, const char *file)
104 {
105         Evas_Object *ic;
106
107         ic = elm_icon_add(box);
108         if (!ic) {
109                 _ERR("failed to create icon");
110                 return;
111         }
112
113         elm_image_file_set(ic, file, NULL);
114         elm_image_resizable_set(ic, EINA_FALSE, EINA_FALSE);
115         elm_image_no_scale_set(ic, EINA_TRUE);
116         evas_object_show(ic);
117
118         elm_box_pack_end(box, ic);
119 }
120
121 static void _pack_icon_box(Evas_Object *obj,
122                 const struct tv_channel_info *channel_info)
123 {
124         Evas_Object *box;
125
126         box = elm_box_add(obj);
127         if (!box) {
128                 _ERR("failed to create box");
129                 return;
130         }
131         evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND,
132                         EVAS_HINT_EXPAND);
133         elm_box_horizontal_set(box, EINA_TRUE);
134         elm_box_padding_set(box, STATUS_BOX_PADDING, 0);
135         elm_box_align_set(box, 1.0, 0.5);
136         elm_object_part_content_set(obj, PART_CHANNELINFO_STATUS, box);
137
138         if (channel_info->locked)
139                 _add_icon(box, IMG_LOCKED_NOR);
140         if (channel_info->favorite)
141                 _add_icon(box, IMG_FAVORITE_NOR);
142 }
143
144 static void _load_channel_text(Evas_Object *obj,
145                 const struct tv_channel_info *channel_info)
146 {
147         char buf[BUF_MAX];
148
149         if (channel_info->channel_minor > 0 &&
150                         channel_info->channel_minor < MINOR_MAX)
151                 snprintf(buf, sizeof(buf), "%lu-%lu %s",
152                                 channel_info->channel_major,
153                                 channel_info->channel_minor,
154                                 channel_info->channel_name);
155         else
156                 snprintf(buf, sizeof(buf), "%lu %s",
157                                 channel_info->channel_major,
158                                 channel_info->channel_name);
159
160         elm_object_part_text_set(obj,
161                         PART_CHANNELINFO_CHANNEL, buf);
162
163         elm_object_part_text_set(obj,
164                         PART_CHANNELINFO_TITLE,
165                         STR_NOTITLE);
166         elm_object_part_text_set(obj,
167                         PART_CHANNELINFO_TIME,
168                         STR_NOTIME);
169 }
170
171 static void _load_program_info(Evas_Object *obj,
172                 const struct tv_program_info *prog)
173 {
174         char buf[BUF_MAX];
175         int r;
176
177         if (prog->start_time && prog->end_time) {
178                 r = _get_program_time(buf, sizeof(buf),
179                                 prog->start_time,
180                                 prog->end_time);
181                 if (!r)
182                         elm_object_part_text_set(obj,
183                                         PART_CHANNELINFO_TIME, buf);
184         }
185
186         if (strlen(prog->prog_title) > 0)
187                 elm_object_part_text_set(obj,
188                                 PART_CHANNELINFO_TITLE, prog->prog_title);
189 }
190
191 static void _tv_program_cb(Eina_List *prog_list, void *data)
192 {
193         Evas_Object *obj;
194         struct tv_program_info *prog = NULL;
195
196         if (!data) {
197                 _ERR("failed to get data");
198                 return;
199         }
200
201         obj = data;
202
203         prog = (struct tv_program_info *) eina_list_nth(prog_list, 0);
204         if (prog)
205                 _load_program_info(obj, prog);
206         else
207                 _ERR("failed to get tv_program_info");
208
209         viewmgr_update_view(VIEW_CHANNELINFO,
210                         UPDATE_TYPE_TIMER, START_HIDE_TIMER);
211 }
212
213 void draw_channel_info(Evas_Object *obj,
214                 const struct tv_channel_info *channel_info)
215 {
216         struct tv_program_request *prog_req;
217         int r;
218         int current_service;
219
220         if (!obj || !channel_info) {
221                 _ERR("Invalid argument");
222
223                 return;
224         }
225
226         r = tv_get_current_service_id(&current_service);
227         if (r < 0)
228                 current_service = -1;
229
230         viewmgr_update_view(VIEW_CHANNELINFO,
231                         UPDATE_TYPE_TIMER, (void *)STOP_HIDE_TIMER);
232
233         _load_channel_text(obj, channel_info);
234         _pack_icon_box(obj, channel_info);
235
236         prog_req = calloc(1, sizeof(*prog_req));
237         prog_req->tv_program_cb = _tv_program_cb;
238         prog_req->user_data = obj;
239
240         if (channel_info->service_id == current_service)
241                 r = tv_epg_get_program(channel_info->service_id, prog_req);
242         else
243                 r = tv_epg_get_cache_program(channel_info->service_id,
244                                 prog_req);
245
246         if (r < 0)
247                 viewmgr_update_view(VIEW_CHANNELINFO,
248                                 UPDATE_TYPE_TIMER, START_HIDE_TIMER);
249 }
250
251 static void _hide_current_layout(struct _priv *priv)
252 {
253         if (!priv->current_layout)
254                 return;
255
256         layoutmgr_hide_layout(priv->lmgr, priv->current_layout);
257         priv->current_layout = NULL;
258 }
259
260 static void _set_current_layout(struct _priv *priv, const char *layout_id)
261 {
262         if (priv->current_layout && layout_id &&
263                         !strcmp(priv->current_layout, layout_id))
264                 return;
265
266         if (priv->current_layout)
267                 layoutmgr_hide_layout(priv->lmgr, priv->current_layout);
268
269         layoutmgr_show_layout(priv->lmgr, layout_id);
270         priv->current_layout = layout_id;
271 }
272
273 static Evas_Object *_create(Evas_Object *win, void *data)
274 {
275         struct _priv *priv;
276
277         if (!win) {
278                 _ERR("failed to get win object");
279                 return NULL;
280         }
281
282         priv = calloc(1, sizeof(*priv));
283         if (!priv) {
284                 _ERR("failed to allocate priv");
285                 return NULL;
286         }
287
288         priv->base = elm_layout_add(win);
289         if (!priv->base) {
290                 _ERR("failed to create base object");
291                 free(priv);
292                 return NULL;
293         }
294         elm_layout_file_set(priv->base, EDJEFILE, GRP_VIEW_CHANNELINFO);
295
296         evas_object_size_hint_weight_set(priv->base,
297                         EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
298         elm_win_resize_object_add(win, priv->base);
299
300         priv->lmgr = layoutmgr_create(priv->base);
301         layoutmgr_add_layout(priv->lmgr, layout_channelinfo_get_lclass(), NULL);
302         layoutmgr_add_layout(priv->lmgr,
303                         layout_channelinfo_list_get_lclass(), NULL);
304         layoutmgr_add_layout(priv->lmgr,
305                         layout_channelinfo_search_get_lclass(), NULL);
306
307         viewmgr_set_view_data(VIEW_CHANNELINFO, priv);
308
309         return priv->base;
310 }
311
312 static void _show(void *view_data)
313 {
314         struct _priv *priv;
315
316         if (!view_data) {
317                 _ERR("failed to get view data");
318                 return;
319         }
320
321         priv = view_data;
322
323         evas_object_show(priv->base);
324 }
325
326 static void _hide(void *view_data)
327 {
328         struct _priv *priv;
329
330         if (!view_data) {
331                 _ERR("failed to get view data");
332                 return;
333         }
334
335         priv = view_data;
336
337         _hide_current_layout(priv);
338
339         evas_object_hide(priv->base);
340 }
341
342 static void _destroy(void *view_data)
343 {
344         struct _priv *priv;
345
346         if (!view_data) {
347                 _ERR("failed to get view data");
348                 return;
349         }
350
351         priv = view_data;
352
353         layoutmgr_remove_layout(priv->lmgr, LAYOUT_CHANNELINFO);
354         layoutmgr_remove_layout(priv->lmgr, LAYOUT_CHANNELINFO_LIST);
355         layoutmgr_remove_layout(priv->lmgr, LAYOUT_CHANNELINFO_SEARCH);
356         layoutmgr_destroy(priv->lmgr);
357
358         evas_object_del(priv->base);
359
360         free(priv);
361 }
362
363 static void _update(void *view_data, int type, void *data)
364 {
365         struct _priv *priv;
366
367         if (!view_data) {
368                 _ERR("failed to get view data");
369                 return;
370         }
371
372         priv = view_data;
373
374         if (type == UPDATE_TYPE_TIMER) {
375                 switch ((int) data) {
376                 case START_HIDE_TIMER:
377                         _start_hide_timer(priv);
378                         break;
379                 case STOP_HIDE_TIMER:
380                         _stop_hide_timer(priv);
381                         break;
382                 }
383         } else if (type == UPDATE_TYPE_INPUT_KEY_DOWN) {
384                 Evas_Event_Key_Down *ev = data;
385
386                 if (!ev) {
387                         _ERR("failed to get ev");
388                         return;
389                 }
390
391                 if (!strcmp(ev->keyname, KEY_ENTER) ||
392                                 !strcmp(ev->keyname, KEY_ENTER_REMOTE)) {
393                         if (!priv->current_layout)
394                                 _set_current_layout(priv, LAYOUT_CHANNELINFO);
395                         else
396                                 _set_current_layout(priv,
397                                                 LAYOUT_CHANNELINFO_SEARCH);
398                 } else if (!strcmp(ev->keyname, KEY_CHANNELUP) ||
399                                 !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE) ||
400                                 !strcmp(ev->keyname, KEY_CHANNELDOWN) ||
401                                 !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) {
402                         _set_current_layout(priv, LAYOUT_CHANNELINFO_LIST);
403                         layoutmgr_update_layout(priv->lmgr,
404                                         LAYOUT_CHANNELINFO_LIST, type, ev);
405                 }
406         } else if (type == UPDATE_TYPE_INPUT_KEY_UP) {
407                 Evas_Event_Key_Up *ev = data;
408
409                 if (!ev) {
410                         _ERR("failed to get ev");
411                         return;
412                 }
413
414                 if (!strcmp(ev->keyname, KEY_CHANNELUP) ||
415                                 !strcmp(ev->keyname, KEY_CHANNELUP_REMOTE) ||
416                                 !strcmp(ev->keyname, KEY_CHANNELDOWN) ||
417                                 !strcmp(ev->keyname, KEY_CHANNELDOWN_REMOTE)) {
418                         _set_current_layout(priv, LAYOUT_CHANNELINFO_LIST);
419                         layoutmgr_update_layout(priv->lmgr,
420                                         LAYOUT_CHANNELINFO_LIST, type, ev);
421                 }
422         }
423 }
424
425 static view_class vclass = {
426         .view_id = VIEW_CHANNELINFO,
427         .create = _create,
428         .show = _show,
429         .hide = _hide,
430         .destroy = _destroy,
431         .update = _update
432 };
433
434 view_class *view_channelinfo_get_vclass(void)
435 {
436         return &vclass;
437 }