49c30fd78e32054d6fbcc5cfae53f1395aff2039
[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_media.h>
21 #include <gridmgr.h>
22 #include <layoutmgr.h>
23 #include <viewmgr.h>
24
25 #include "define.h"
26 #include "view.h"
27 #include "data/mediadata.h"
28 #include "util/listmgr.h"
29 #include "util/progressbar.h"
30 #include "util/util.h"
31
32 #define LIST_MEDIA_COND "media_type=1 AND copyright NOT LIKE \"Unknown\""
33
34 #define TEXT_NOCONTENT "No Movies"
35 #define TEXT_RECENTLY_WATCHED "Recently watched"
36
37 #define GRID_PADDING 26
38 #define GRID_ITEM_X (378 + GRID_PADDING)
39 #define GRID_ITEM_Y (294 + GRID_PADDING)
40 #define GRID_NUM_ITEM 2
41
42 #define BOX_PADDING (62 - GRID_PADDING)
43
44 #define IMAGE_FAVORITE_ALPHA 150
45
46 struct _priv {
47         Evas_Object *base;
48         Evas_Object *layout;
49         Evas_Object *box;
50         Evas_Object *menu_btn;
51
52         layoutmgr *lmgr;
53
54         struct listmgr *listmgr;
55         struct listmgr_data *ldata;
56
57         struct mediadata *md;
58
59         struct progressbar *prog;
60
61         Eina_List *media_list;
62         int cur_index;
63
64         app_media *recent_info;
65 };
66
67 static char *_grid_text_get(void *data, Evas_Object *obj, const char *part)
68 {
69         app_media *am;
70         app_media_info *info;
71
72         if (!data)
73                 return NULL;
74
75         am = data;
76
77         if (!strcmp(part, PART_ELM_TEXT_TITLE)) {
78                 info = app_media_get_info(am);
79                 if (!info) {
80                         _ERR("failed to get media info");
81                         return NULL;
82                 }
83
84                 return strdup(info->title);
85         }
86
87         return NULL;
88 }
89
90 static Evas_Object *_grid_content_get(void *data,
91                         Evas_Object *obj, const char *part)
92 {
93         Evas_Object *image;
94         app_media *am;
95         app_media_info *info;
96
97         if (!data)
98                 return NULL;
99
100         am = data;
101         info = app_media_get_info(am);
102         if (!info) {
103                 _ERR("failed to get media info");
104                 return NULL;
105         }
106
107         image = NULL;
108         if (!strcmp(part, PART_ELM_SWALLOW_THUMBNAIL)) {
109                 image = util_add_image(obj, info->thumbnail_path);
110                 if (!image) {
111                         _ERR("failed to create image object");
112                         return NULL;
113                 }
114
115                 evas_object_show(image);
116         } else if (!strcmp(part, PART_ELM_SWALLOW_FAVORITE)) {
117                 int r, g, b, a;
118
119                 if (!info->favorite)
120                         return NULL;
121
122                 image = util_add_image(obj, IMAGE_THUMBNAIL_FAVORITE);
123                 if (!image) {
124                         _ERR("failed to create image object");
125                         return NULL;
126                 }
127
128                 evas_object_color_get(image, &r, &g, &b, &a);
129                 evas_object_color_set(image, r, g, b, IMAGE_FAVORITE_ALPHA);
130
131                 evas_object_show(image);
132         }
133
134         return image;
135 }
136
137 static struct grid_class _gclass = {
138         .item_style = STYLE_GRID_MOVIE_ITEM,
139         .text_get = _grid_text_get,
140         .content_get = _grid_content_get
141 };
142
143 static bool _update_recent(void *data, Evas_Object *base)
144 {
145         Evas_Object *recent, *image;
146         app_media_info *info;
147         struct tm tm;
148         struct _priv *priv;
149         char buf[32];
150
151         if (!data || !base) {
152                 _ERR("invalid argument");
153                 return false;
154         }
155
156         priv = data;
157
158         recent = elm_object_part_content_get(base, PART_ITEM_CONTENT);
159         if (!recent) {
160                 _ERR("failed to get recent content part");
161                 return false;
162         }
163
164         image = elm_object_part_content_get(recent,
165                                 PART_RECENT_CONTENT_THUMBNAIL);
166         if (!image) {
167                 _ERR("failed to get image object");
168                 return false;
169         }
170
171         info = app_media_get_info(priv->recent_info);
172         if (!info) {
173                 _ERR("failed to get app media info");
174                 return false;
175         }
176
177         elm_image_file_set(image, info->thumbnail_path, NULL);
178         elm_image_aspect_fixed_set(image, EINA_FALSE);
179
180         elm_object_part_text_set(recent, PART_RECENT_CONTENT_TITLE,
181                                 info->title);
182
183         localtime_r(&info->played_time, &tm);
184         strftime(buf, sizeof(buf), "%Y.%m.%d", &tm);
185         elm_object_part_text_set(recent, PART_RECENT_CONTENT_DATE, buf);
186
187         if (info->favorite)
188                 elm_object_signal_emit(recent, SIG_RECENT_SHOW_FAV,
189                                         SIG_SOURCE_SRC);
190         else
191                 elm_object_signal_emit(recent, SIG_RECENT_HIDE_FAV,
192                                         SIG_SOURCE_SRC);
193
194         progressbar_reset(priv->prog, info->video->position,
195                                 info->video->duration);
196
197         progressbar_show(priv->prog);
198
199         return true;
200 }
201
202 static bool _draw_recent_title(Evas_Object *base)
203 {
204         Evas_Object *btn;
205
206         btn = elm_button_add(base);
207         if (!btn) {
208                 _ERR("failed to create button object");
209                 return false;
210         }
211
212         elm_object_style_set(btn, STYLE_BTN_INDEX);
213         elm_object_text_set(btn, TEXT_RECENTLY_WATCHED);
214
215         elm_object_part_content_set(base, PART_ITEM_TITLE, btn);
216
217         return true;
218 }
219
220 static bool _draw_recent_content(struct _priv *priv, Evas_Object *base)
221 {
222         Evas_Object *btn, *image;
223         struct progressbar *prog;
224
225         btn = elm_button_add(base);
226         if (!btn) {
227                 _ERR("failed to create button object");
228                 return false;
229         }
230
231         elm_object_style_set(btn, STYLE_BTN_RECENT_CONTENT);
232
233         image = elm_image_add(btn);
234         if (!image) {
235                 _ERR("failed to create image object");
236                 return false;
237         }
238
239         elm_object_part_content_set(btn, PART_RECENT_CONTENT_THUMBNAIL, image);
240
241         elm_object_part_content_set(base, PART_ITEM_CONTENT, btn);
242
243         prog = progressbar_create(btn, STYLE_BASE_PROGRESS);
244         if (!prog) {
245                 _ERR("failed to create progressbar");
246                 return false;
247         }
248
249         progressbar_set_parts(prog, PART_RECENT_CONTENT_SLIDER,
250                                 PART_RECENT_CONTENT_TOTAL,
251                                 PART_RECENT_CONTENT_PROGRESS, "");
252
253         priv->prog = prog;
254
255         return true;
256 }
257
258 static bool _draw_recent(void *data, Evas_Object *base)
259 {
260         struct _priv *priv;
261
262         if (!data || !base) {
263                 _ERR("invalid argument");
264                 return false;
265         }
266
267         priv = data;
268
269         if (!_draw_recent_title(base)) {
270                 _ERR("failed to draw recent title");
271                 return false;
272         }
273
274         if (!_draw_recent_content(priv, base)) {
275                 _ERR("failed to draw recent content");
276                 return false;
277         }
278
279         return true;
280 }
281
282 static void _item_selected_cb(struct _priv *priv, app_media *am)
283 {
284         struct view_update_data vdata;
285
286         vdata.list = mediadata_get_medialist(priv->md);
287         vdata.index = util_get_media_index(vdata.list, am);
288         priv->cur_index = vdata.index;
289
290         viewmgr_update_view(VIEW_VIEWER, UPDATE_CONTENT, &vdata);
291         viewmgr_push_view(VIEW_VIEWER);
292 }
293
294 static void _recent_selected_cb(void *data, Evas_Object *obj)
295 {
296         struct _priv *priv;
297
298         if (!data || !obj)
299                 return;
300
301         priv = data;
302
303         _item_selected_cb(priv, priv->recent_info);
304 }
305
306 static void _grid_selected_cb(void *data, Elm_Object_Item *it)
307 {
308         app_media *am;
309         struct _priv *priv;
310
311         if (!data || !it) {
312                 _ERR("invalid argument");
313                 return;
314         }
315
316         priv = data;
317
318         am = elm_object_item_data_get(it);
319         if (!am) {
320                 _ERR("failed to get app media");
321                 return;
322         }
323
324         _item_selected_cb(priv, am);
325 }
326
327 static struct listmgr_data *_create_listmgr_data(struct _priv *priv)
328 {
329         struct listmgr_data *data;
330         struct play_info_ops *pops;
331         struct grid_ops *gops;
332
333         data = calloc(1, sizeof(*data));
334         if (!data)
335                 goto err;
336
337         data->menu_btn = priv->menu_btn;
338
339         data->grid_item_x = GRID_ITEM_X;
340         data->grid_item_y = GRID_ITEM_Y;
341         data->grid_num_item = GRID_NUM_ITEM;
342         data->box_padding = BOX_PADDING;
343
344         pops = calloc(1, sizeof(*pops));
345         if (!pops)
346                 goto err;
347
348         pops->draw = _draw_recent;
349         pops->update = _update_recent;
350         pops->selected_cb = _recent_selected_cb;
351         pops->ops_data = priv;
352
353         gops = calloc(1, sizeof(*gops));
354         if (!gops)
355                 goto err;
356
357         gops->gclass = &_gclass;
358         gops->selected_cb = _grid_selected_cb;
359         gops->ops_data = priv;
360
361         data->pops = pops;
362         data->gops = gops;
363
364         return data;
365
366 err:
367         _ERR("failed to allocate memory");
368         return NULL;
369 }
370
371 static void _update_content_info(struct _priv *priv)
372 {
373         int count;
374         char buf[128];
375
376         count = mediadata_get_media_count(priv->md, E_MEDIA_VIDEO);
377         if (count < 0) {
378                 _ERR("failed to get media count");
379                 return;
380         }
381
382         snprintf(buf, sizeof(buf), "%d Movies", count);
383
384         elm_object_part_text_set(priv->layout, PART_CONTENT_INFO, buf);
385 }
386
387 static void _update_content_list(struct _priv *priv)
388 {
389         Eina_List *list;
390
391         if (priv->media_list)
392                 return;
393
394         list = mediadata_get_list(priv->md, E_LIST_NAME);
395         if (!list) {
396                 elm_object_part_text_set(priv->layout,
397                                 PART_NOCONTENT, TEXT_NOCONTENT);
398                 return;
399         }
400
401         if (!listmgr_update_content_list(priv->listmgr, list)) {
402                 _ERR("failed to update list area");
403                 return;
404         }
405
406         priv->media_list = list;
407
408         _update_content_info(priv);
409 }
410
411 static void _update_recent_item(struct _priv *priv, int index)
412 {
413         Eina_List *list;
414         app_media *am;
415         app_media_info *info;
416
417         list = mediadata_get_medialist(priv->md);
418         am = eina_list_nth(list, index);
419         if (!am) {
420                 _ERR("failed to get app media");
421                 return;
422         }
423
424         info = app_media_get_info(am);
425         if (!info) {
426                 _ERR("failed to get app media info");
427                 return;
428         }
429
430         priv->recent_info = am;
431
432         if (!listmgr_update_play_info(priv->listmgr, info))
433                 _ERR("failed to update recently watched item");
434 }
435
436 static bool _create(layoutmgr *lmgr, void *data)
437 {
438         struct listmgr *listmgr;
439         struct listmgr_data *ldata;
440         struct mediadata *md;
441         struct _priv *priv;
442         Evas_Object *base, *layout;
443
444         if (!lmgr) {
445                 _ERR("failed to get layoutmgr");
446                 return false;
447         }
448
449         if (!data) {
450                 _ERR("invalid argument");
451                 return false;
452         }
453
454         priv = calloc(1, sizeof(*priv));
455         if (!priv) {
456                 _ERR("failed to allocate priv");
457                 return false;
458         }
459
460         priv->menu_btn = (Evas_Object *)data;
461
462         base = layoutmgr_get_base(lmgr);
463         if (!base) {
464                 _ERR("failed to get base object");
465                 goto err;
466         }
467
468         layout = elm_layout_add(base);
469         if (!layout) {
470                 _ERR("failed to create layout");
471                 goto err;
472         }
473
474         if (!elm_layout_file_set(layout, EDJEFILE, GRP_MOVIE_LAYOUT)) {
475                 _ERR("failed to set layout file");
476                 goto err2;
477         }
478
479         ldata = _create_listmgr_data(priv);
480         if (!ldata) {
481                 _ERR("failed to create listmgr data");
482                 goto err2;
483         }
484
485         listmgr = listmgr_create(layout, (void *)ldata);
486         if (!listmgr) {
487                 _ERR("failed to create listmgr");
488                 goto err3;
489         }
490
491         md = mediadata_create(LIST_MEDIA_COND, E_SOURCE_ALL, E_SORT_NAME);
492         if (!md) {
493                 _ERR("failed to create mediadata");
494                 listmgr_destroy(listmgr);
495                 goto err3;
496         }
497
498         priv->base = base;
499         priv->layout = layout;
500         priv->lmgr = lmgr;
501         priv->listmgr = listmgr;
502         priv->ldata = ldata;
503         priv->md = md;
504
505         layoutmgr_set_layout_data(lmgr, LAYOUT_MOVIE, priv);
506
507         if (!listmgr_draw_list_area(priv->listmgr)) {
508                 _ERR("failed to draw list area");
509                 mediadata_destroy(md);
510                 listmgr_destroy(listmgr);
511                 goto err3;
512         }
513
514         return true;
515
516 err3:
517         free(ldata);
518 err2:
519         evas_object_del(layout);
520 err:
521         free(priv);
522         return false;
523 }
524
525 static void _destroy(void *layout_data)
526 {
527         struct _priv *priv;
528
529         if (!layout_data) {
530                 _ERR("failed to get layout data");
531                 return;
532         }
533
534         priv = layout_data;
535
536         progressbar_destroy(priv->prog);
537
538         mediadata_free_list(priv->media_list);
539         mediadata_destroy(priv->md);
540
541         listmgr_destroy(priv->listmgr);
542         free(priv->ldata->pops);
543         free(priv->ldata->gops);
544         free(priv->ldata);
545
546         evas_object_del(priv->layout);
547
548         free(priv);
549 }
550
551 static void _show(void *layout_data)
552 {
553         struct _priv *priv;
554
555         if (!layout_data) {
556                 _ERR("failed to layout data");
557                 return;
558         }
559
560         priv = layout_data;
561
562         evas_object_show(priv->layout);
563         elm_object_part_content_set(priv->base,
564                         PART_THUMBNAIL_AREA, priv->layout);
565 }
566
567 static void _hide(void *layout_data)
568 {
569         struct _priv *priv;
570
571         if (!layout_data) {
572                 _ERR("failed to get layout data");
573                 return;
574         }
575
576         priv = layout_data;
577
578         evas_object_hide(priv->layout);
579         elm_object_part_content_unset(priv->base, PART_THUMBNAIL_AREA);
580 }
581
582 static void _update(void *layout_data, int update_type, void *data)
583 {
584         struct view_update_data *vdata;
585         struct _priv *priv;
586
587         if (!layout_data) {
588                 _ERR("failed to get layout data");
589                 return;
590         }
591
592         priv = layout_data;
593         vdata = data;
594
595         switch (update_type) {
596         case UPDATE_CONTENT:
597                 _update_content_list(priv);
598                 break;
599         case UPDATE_FOCUS:
600                 if (!vdata) {
601                         _ERR("invalid argument");
602                         return;
603                 }
604
605                 listmgr_focus_play_info(priv->listmgr);
606                 _update_recent_item(priv, vdata->index);
607                 break;
608         case UPDATE_RESUME:
609                 listmgr_focus_content_list(priv->listmgr,
610                                 priv->cur_index, false);
611                 break;
612         default:
613                 break;
614         }
615 }
616
617 static layout_class _lclass = {
618         .layout_id = LAYOUT_MOVIE,
619         .create = _create,
620         .show = _show,
621         .hide = _hide,
622         .destroy = _destroy,
623         .update = _update,
624 };
625
626 layout_class *layout_movie_get_lclass(void)
627 {
628         return &_lclass;
629 }