79416cd891ee1025e54f4b8b95bd82dcd1ccef81
[profile/tv/apps/native/air_mediahub.git] / src / layout / movie.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 <media_content.h>
19 #include <app_debug.h>
20 #include <app_contents.h>
21 #include <app_media.h>
22 #include <gridmgr.h>
23 #include <inputmgr.h>
24 #include <layoutmgr.h>
25 #include <viewmgr.h>
26
27 #include "define.h"
28 #include "layout.h"
29 #include "view.h"
30 #include "data/datamgr.h"
31 #include "grid/grid.h"
32 #include "util/listmgr.h"
33 #include "util/progressbar.h"
34 #include "util/util.h"
35
36 #define TEXT_NOCONTENT "No Movies"
37 #define TEXT_RECENTLY_WATCHED "Recently watched"
38
39 #define GRID_PADDING 26
40 #define GRID_ITEM_X (378 + GRID_PADDING)
41 #define GRID_ITEM_Y (294 + GRID_PADDING)
42 #define GRID_NUM_ITEM 2
43
44 #define BOX_PADDING (62 - GRID_PADDING)
45
46 struct _priv {
47         Evas_Object *base;
48         Evas_Object *layout;
49         Evas_Object *box;
50         Evas_Object *menu_btn;
51         Evas_Object *view_btn;
52
53         layoutmgr *lmgr;
54
55         struct listmgr *listmgr;
56         struct listmgr_data *ldata;
57
58         struct datamgr *dmgr[E_DATA_MAX];
59
60         struct progressbar *prog;
61
62         Eina_List *media_list;
63
64         app_media *recent_info;
65
66         int view_mode;
67         struct grid_data *gdata;
68 };
69
70 static bool _update_recent_info(Evas_Object *base, app_media_info *info)
71 {
72         Evas_Object *image, *text_bg;
73         struct color_data bg;
74         struct tm tm;
75         char buf[32];
76
77         image = elm_object_part_content_get(base,
78                                 PART_RECENT_CONTENT_THUMBNAIL);
79         if (!image) {
80                 _ERR("failed to get image object");
81                 return false;
82         }
83
84         text_bg = elm_object_part_content_get(base, PART_RECENT_CONTENT_TEXTBG);
85         if (!text_bg) {
86                 _ERR("failed to get textbg part");
87                 return false;
88         }
89
90         elm_image_file_set(image, info->thumbnail_path, NULL);
91         elm_image_aspect_fixed_set(image, EINA_FALSE);
92
93         app_contents_get_color(info->title, NULL, &bg);
94         evas_object_color_set(text_bg, bg.r, bg.g, bg.b, bg.a);
95
96         elm_object_part_text_set(base, PART_RECENT_CONTENT_TITLE,
97                                 info->title);
98
99         localtime_r(&info->played_time, &tm);
100         strftime(buf, sizeof(buf), "%Y.%m.%d", &tm);
101         elm_object_part_text_set(base, PART_RECENT_CONTENT_DATE, buf);
102
103         if (info->favorite)
104                 elm_object_signal_emit(base, SIG_RECENT_SHOW_FAV,
105                                         SIG_SOURCE_SRC);
106         else
107                 elm_object_signal_emit(base, SIG_RECENT_HIDE_FAV,
108                                         SIG_SOURCE_SRC);
109
110         return true;
111 }
112
113 static bool _update_recent(void *data, Evas_Object *base)
114 {
115         Evas_Object *recent;
116         app_media_info *info;
117         struct _priv *priv;
118
119         if (!data || !base) {
120                 _ERR("invalid argument");
121                 return false;
122         }
123
124         priv = data;
125
126         recent = elm_object_part_content_get(base, PART_ITEM_CONTENT);
127         if (!recent) {
128                 _ERR("failed to get recent content part");
129                 return false;
130         }
131
132         info = app_media_get_info(priv->recent_info);
133         if (!info) {
134                 _ERR("failed to get app media info");
135                 return false;
136         }
137
138         if (!_update_recent_info(recent, info)) {
139                 _ERR("failed to update recent info");
140                 return false;
141         }
142
143         progressbar_reset(priv->prog, info->video->position,
144                                 info->video->duration);
145
146         progressbar_show(priv->prog);
147
148         return true;
149 }
150
151 static bool _draw_recent_title(Evas_Object *base)
152 {
153         Evas_Object *btn;
154
155         btn = elm_button_add(base);
156         if (!btn) {
157                 _ERR("failed to create button object");
158                 return false;
159         }
160
161         elm_object_style_set(btn, STYLE_BTN_INDEX);
162         elm_object_text_set(btn, TEXT_RECENTLY_WATCHED);
163
164         elm_object_part_content_set(base, PART_ITEM_TITLE, btn);
165
166         return true;
167 }
168
169 static bool _draw_recent_content(struct _priv *priv, Evas_Object *base)
170 {
171         Evas_Object *btn, *image, *text_bg;
172         struct progressbar *prog;
173
174         btn = elm_button_add(base);
175         if (!btn) {
176                 _ERR("failed to create button object");
177                 return false;
178         }
179
180         elm_object_style_set(btn, STYLE_BTN_RECENT_CONTENT);
181
182         image = elm_image_add(btn);
183         if (!image) {
184                 _ERR("failed to create image object");
185                 return false;
186         }
187
188         text_bg = evas_object_rectangle_add(btn);
189         if (!text_bg) {
190                 _ERR("failed to create rectangle object");
191                 return false;
192         }
193
194         elm_object_part_content_set(btn, PART_RECENT_CONTENT_THUMBNAIL, image);
195         elm_object_part_content_set(btn, PART_RECENT_CONTENT_TEXTBG, text_bg);
196
197         elm_object_part_content_set(base, PART_ITEM_CONTENT, btn);
198
199         prog = progressbar_create(btn, STYLE_BASE_PROGRESS);
200         if (!prog) {
201                 _ERR("failed to create progressbar");
202                 return false;
203         }
204
205         progressbar_set_parts(prog, PART_RECENT_CONTENT_SLIDER,
206                                 PART_RECENT_CONTENT_TOTAL,
207                                 PART_RECENT_CONTENT_PROGRESS, "");
208
209         priv->prog = prog;
210
211         return true;
212 }
213
214 static bool _draw_recent(void *data, Evas_Object *base)
215 {
216         struct _priv *priv;
217
218         if (!data || !base) {
219                 _ERR("invalid argument");
220                 return false;
221         }
222
223         priv = data;
224
225         if (!_draw_recent_title(base)) {
226                 _ERR("failed to draw recent title");
227                 return false;
228         }
229
230         if (!_draw_recent_content(priv, base)) {
231                 _ERR("failed to draw recent content");
232                 return false;
233         }
234
235         return true;
236 }
237
238 static void _recent_item_selected(struct _priv *priv, app_media *am)
239 {
240         app_media_info *info;
241         struct view_update_data vdata;
242         struct datamgr *dmgr;
243
244         info = app_media_get_info(am);
245         if (!info) {
246                 _ERR("failed to get app media info");
247                 return;
248         }
249
250         dmgr = priv->dmgr[E_DATA_MEDIA];
251         if (!dmgr)
252                 return;
253
254         vdata.list = dmgr->ops->get_list(dmgr->handle, E_LIST_MEDIA, NULL);
255         vdata.index = util_get_media_index_from_id(vdata.list, info->media_id);
256         vdata.id = VIEW_BASE;
257
258         viewmgr_update_view(VIEW_VIEWER, UPDATE_CONTENT, &vdata);
259         viewmgr_push_view(VIEW_VIEWER);
260 }
261
262 static void _recent_key_down_cb(void *data, Evas_Object *obj,
263                         Evas_Event_Key_Down *ev)
264 {
265         struct view_update_data vdata;
266         struct datamgr *dmgr;
267         struct _priv *priv;
268
269         if (!data || !ev)
270                 return;
271
272         priv = data;
273
274         dmgr = priv->dmgr[E_DATA_MEDIA];
275         if (!dmgr)
276                 return;
277
278         if (!strcmp(ev->keyname, KEY_MENU) ||
279                 !strcmp(ev->keyname, KEY_CONTEXT_MENU)) {
280                 vdata.list = dmgr->ops->get_list(dmgr->handle,
281                                         E_LIST_MEDIA, NULL);
282                 vdata.index = util_get_media_index(vdata.list,
283                                         priv->recent_info);
284                 vdata.id = VIEW_BASE;
285
286                 viewmgr_update_view(VIEW_ACTION_MENU, UPDATE_CONTENT, &vdata);
287                 viewmgr_show_view(VIEW_ACTION_MENU);
288         }
289 }
290
291 static void _recent_selected_cb(void *data, Evas_Object *obj)
292 {
293         struct _priv *priv;
294         struct view_update_data vdata;
295         struct datamgr *dmgr;
296
297         if (!data || !obj)
298                 return;
299
300         priv = data;
301
302         dmgr = priv->dmgr[E_DATA_MEDIA];
303         if (!dmgr)
304                 return;
305
306         vdata.list = dmgr->ops->get_list(dmgr->handle, E_LIST_MEDIA, NULL);
307         vdata.index = util_get_media_index(vdata.list, priv->recent_info);
308         vdata.id = VIEW_BASE;
309
310         viewmgr_update_view(VIEW_VIEWER, UPDATE_CONTENT, &vdata);
311         viewmgr_push_view(VIEW_VIEWER);
312 }
313
314 static struct listmgr_data *_create_listmgr_data(struct _priv *priv)
315 {
316         struct listmgr_data *data;
317         struct play_info_data *pdata;
318
319         data = calloc(1, sizeof(*data));
320         if (!data)
321                 goto err;
322
323         data->menu_btn = priv->menu_btn;
324         data->view_btn = priv->view_btn;
325
326         pdata = calloc(1, sizeof(*pdata));
327         if (!pdata)
328                 goto err2;
329
330         pdata->draw = _draw_recent;
331         pdata->update = _update_recent;
332         pdata->key_down_cb = _recent_key_down_cb;
333         pdata->selected_cb = _recent_selected_cb;
334         pdata->cb_data = priv;
335
336         data->pdata = pdata;
337
338         return data;
339
340 err2:
341         free(data);
342 err:
343         _ERR("failed to allocate memory");
344         return NULL;
345 }
346
347 static void _update_content_info(struct _priv *priv)
348 {
349         struct datamgr *dmgr;
350         char buf[128];
351
352         dmgr = priv->dmgr[E_DATA_MEDIA];
353         if (!dmgr)
354                 return;
355
356         priv->gdata->get_item_info(dmgr, priv->media_list, buf, sizeof(buf));
357
358         elm_object_part_text_set(priv->base, PART_BASE_CONTENT_INFO, buf);
359 }
360
361 static void _clear_content_list(struct _priv *priv)
362 {
363         if (priv->media_list) {
364                 priv->gdata->free_item_list(priv->dmgr[E_DATA_MEDIA],
365                                 priv->media_list);
366                 priv->media_list = NULL;
367         }
368
369         listmgr_clear_content_list(priv->listmgr);
370 }
371
372 static void _update_content_list(struct _priv *priv)
373 {
374         Eina_List *list;
375
376         if (priv->media_list) {
377                 _update_content_info(priv);
378                 return;
379         }
380
381         priv->gdata = get_movie_grid_data(priv->view_mode);
382
383         list = priv->gdata->get_item_list(priv->dmgr[E_DATA_MEDIA]);
384         if (!list) {
385                 elm_object_part_text_set(priv->layout,
386                                 PART_NOCONTENT, TEXT_NOCONTENT);
387                 return;
388         }
389
390         priv->gdata->data = priv->dmgr[E_DATA_MEDIA];
391
392         if (!listmgr_update_content_list(priv->listmgr, list, priv->gdata)) {
393                 _ERR("failed to update list area");
394                 return;
395         }
396
397         priv->media_list = list;
398
399         _update_content_info(priv);
400 }
401
402 static app_media *_get_recent_item(Eina_List *list)
403 {
404         GList *rlist;
405         app_media *am;
406         struct recent_data *rdata;
407         int r;
408
409         rlist = NULL;
410         am = NULL;
411         r = app_contents_get_recent_list(CONTENTS_MOVIE, 1, &rlist);
412         if (r != APP_CONTENTS_ERROR_NONE) {
413                 _ERR("failed to get movie recent list");
414                 return NULL;
415         }
416
417         rdata = g_list_nth_data(rlist, 0);
418         if (rdata && rdata->id)
419                 am = util_find_media_info(list, rdata->id);
420
421         app_contents_free_recent_list(rlist);
422
423         return am;
424 }
425
426 static void _update_recent_item(struct _priv *priv, const char *id)
427 {
428         Eina_List *list;
429         app_media *am;
430         app_media_info *info;
431         struct datamgr *dmgr;
432
433         dmgr = priv->dmgr[E_DATA_MEDIA];
434         if (!dmgr)
435                 return;
436
437         list = dmgr->ops->get_list(dmgr->handle, E_LIST_MEDIA, NULL);
438
439         if (id)
440                 am = util_find_media_info(list, id);
441         else
442                 am = _get_recent_item(list);
443
444         if (!am) {
445                 _ERR("failed to get app media");
446                 return;
447         }
448
449         info = app_media_get_info(am);
450         if (!info) {
451                 _ERR("failed to get app media info");
452                 return;
453         }
454
455         priv->recent_info = am;
456
457         if (!listmgr_update_play_info(priv->listmgr, info))
458                 _ERR("failed to update recently watched item");
459 }
460
461 static void _destroy_datamgr(struct _priv *priv)
462 {
463         int i;
464
465         for (i = 0; i < E_DATA_MAX; i++)
466                 datamgr_destroy(priv->dmgr[i]);
467 }
468
469 static void _destroy_utils(struct _priv *priv)
470 {
471         _destroy_datamgr(priv);
472
473         listmgr_destroy(priv->listmgr);
474         free(priv->ldata->pdata);
475         free(priv->ldata);
476 }
477
478 static bool _create_utils(struct _priv *priv)
479 {
480         struct listmgr *listmgr;
481         struct listmgr_data *ldata;
482         struct datamgr *dmgr;
483         int i;
484
485         for (i = 0; i < E_DATA_MAX; i++) {
486                 dmgr = datamgr_create(i, MOVIE_MEDIA_COND, E_SOURCE_ALL);
487                 if (!dmgr) {
488                         _ERR("failed to create datamgr");
489                         _destroy_datamgr(priv);
490                         return false;
491                 }
492
493                 priv->dmgr[i] = dmgr;
494         }
495
496         ldata = _create_listmgr_data(priv);
497         if (!ldata) {
498                 _ERR("failed to create listmgr data");
499                 _destroy_datamgr(priv);
500                 return false;
501         }
502
503         listmgr = listmgr_create(priv->layout, (void *)ldata);
504         if (!listmgr) {
505                 _ERR("failed to create listmgr");
506                 _destroy_datamgr(priv);
507                 free(ldata);
508                 return false;
509         }
510
511         priv->ldata = ldata;
512         priv->listmgr = listmgr;
513
514         return true;
515 }
516
517 static bool _create(layoutmgr *lmgr, void *data)
518 {
519         struct layout_data *ld;
520         struct _priv *priv;
521         Evas_Object *base, *layout;
522
523         if (!lmgr) {
524                 _ERR("failed to get layoutmgr");
525                 return false;
526         }
527
528         if (!data) {
529                 _ERR("invalid argument");
530                 return false;
531         }
532
533         ld = data;
534
535         priv = calloc(1, sizeof(*priv));
536         if (!priv) {
537                 _ERR("failed to allocate priv");
538                 return false;
539         }
540
541         base = layoutmgr_get_base(lmgr);
542         if (!base) {
543                 _ERR("failed to get base object");
544                 goto err;
545         }
546
547         layout = elm_layout_add(base);
548         if (!layout) {
549                 _ERR("failed to create layout");
550                 goto err;
551         }
552
553         if (!elm_layout_file_set(layout, EDJEFILE, GRP_MOVIE_LAYOUT)) {
554                 _ERR("failed to set layout file");
555                 goto err2;
556         }
557
558         priv->base = base;
559         priv->layout = layout;
560         priv->menu_btn = ld->top;
561         priv->view_btn = ld->bottom;
562         priv->lmgr = lmgr;
563         priv->gdata = get_movie_grid_data(E_MOVIE_NAME);
564
565         if (!_create_utils(priv)) {
566                 _ERR("failed to create utils");
567                 goto err2;
568         }
569
570         layoutmgr_set_layout_data(lmgr, LAYOUT_MOVIE, priv);
571
572         if (!listmgr_draw_list_area(priv->listmgr)) {
573                 _ERR("failed to draw list area");
574                 goto err3;
575         }
576
577         return true;
578
579 err3:
580         _destroy_utils(priv);
581 err2:
582         evas_object_del(layout);
583 err:
584         free(priv);
585         return false;
586 }
587
588 static void _destroy(void *layout_data)
589 {
590         struct _priv *priv;
591
592         if (!layout_data) {
593                 _ERR("failed to get layout data");
594                 return;
595         }
596
597         priv = layout_data;
598
599         progressbar_destroy(priv->prog);
600
601         priv->gdata->free_item_list(priv->dmgr[E_DATA_MEDIA], priv->media_list);
602
603         _destroy_utils(priv);
604
605         evas_object_del(priv->layout);
606
607         free(priv);
608 }
609
610 static void _show(void *layout_data)
611 {
612         struct _priv *priv;
613
614         if (!layout_data) {
615                 _ERR("failed to layout data");
616                 return;
617         }
618
619         priv = layout_data;
620
621         evas_object_show(priv->layout);
622         elm_object_part_content_set(priv->base,
623                         PART_BASE_THUMBNAIL_AREA, priv->layout);
624 }
625
626 static void _hide(void *layout_data)
627 {
628         struct _priv *priv;
629
630         if (!layout_data) {
631                 _ERR("failed to get layout data");
632                 return;
633         }
634
635         priv = layout_data;
636
637         evas_object_hide(priv->layout);
638         elm_object_part_content_unset(priv->base, PART_BASE_THUMBNAIL_AREA);
639 }
640
641 static void _update(void *layout_data, int update_type, void *data)
642 {
643         struct view_update_data *vdata;
644         struct _priv *priv;
645         int mode;
646
647         if (!layout_data) {
648                 _ERR("failed to get layout data");
649                 return;
650         }
651
652         priv = layout_data;
653
654         switch (update_type) {
655         case UPDATE_CONTENT:
656                 _update_content_list(priv);
657                 _update_recent_item(priv, NULL);
658                 break;
659         case UPDATE_CONTENT_ITEM:
660                 listmgr_update_content_item(priv->listmgr);
661                 _update_recent_item(priv, NULL);
662                 break;
663         case UPDATE_FOCUS:
664                 if (!data) {
665                         _ERR("invalid argument");
666                         return;
667                 }
668
669                 vdata = data;
670
671                 listmgr_focus_play_info(priv->listmgr);
672                 _update_recent_item(priv, vdata->id);
673                 break;
674         case UPDATE_BACK:
675                 listmgr_focus_content_list(priv->listmgr, NULL);
676                 break;
677         case UPDATE_RECENT:
678                 if (!data) {
679                         _ERR("invalid argument");
680                         return;
681                 }
682
683                 _update_content_list(priv);
684                 _recent_item_selected(priv, data);
685                 break;
686         case UPDATE_FOCUS_STATE:
687                 listmgr_set_focus_state(priv->listmgr, EINA_FALSE);
688                 break;
689         case UPDATE_VIEW_MODE:
690                 if (!data) {
691                         _ERR("invalid argument");
692                         return;
693                 }
694
695                 vdata = data;
696                 mode = vdata->index;
697
698                 /* Folder view mode will be implemented later */
699                 if (mode == E_MOVIE_FOLDER)
700                         return;
701
702                 if (mode == priv->view_mode)
703                         return;
704
705                 _clear_content_list(priv);
706
707                 priv->view_mode = mode;
708                 _update_content_list(priv);
709                 break;
710         default:
711                 break;
712         }
713 }
714
715 static layout_class _lclass = {
716         .layout_id = LAYOUT_MOVIE,
717         .create = _create,
718         .show = _show,
719         .hide = _hide,
720         .destroy = _destroy,
721         .update = _update,
722 };
723
724 layout_class *layout_movie_get_lclass(void)
725 {
726         return &_lclass;
727 }