terminate the app when there is no active view
[profile/tv/apps/native/air_mediahub.git] / src / view / viewer.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 <app.h>
18 #include <Elementary.h>
19 #include <app_debug.h>
20 #include <viewmgr.h>
21 #include <layoutmgr.h>
22 #include <inputmgr.h>
23 #include <media_content.h>
24 #include <media_info.h>
25 #include <player.h>
26 #include <app_media.h>
27 #include <app_contents.h>
28
29 #include "define.h"
30 #include "view.h"
31 #include "util/controller.h"
32 #include "util/timeout_handler.h"
33 #include "util/playermgr.h"
34 #include "util/progressbar.h"
35 #include "util/util.h"
36
37 #define STYLE_VIEWER_BTN "viewer_btn"
38 #define PART_VIEWER_BTN "control_btn"
39 #define PLAY_BTN_LOC 1
40
41 #define VIEWER_TIMEOUT 3.0
42 #define VIEWER_SEPARATOR "/ "
43 #define VIDEO_COPYRIGHT "Unknown"
44
45 enum {
46         VIEWER_MOVIE,
47         VIEWER_PHOTO,
48         VIEWER_VIDEO,
49         VIEWER_MAX
50 };
51
52 enum {
53         DIR_NONE,
54         DIR_PREV,
55         DIR_NEXT
56 };
57
58 struct _viewer {
59         struct controller *ctl[VIEWER_MAX];
60         int cur;
61 };
62
63 struct _playlist {
64         Eina_List *list;
65         int cur;
66         int dir;
67 };
68
69 struct _priv {
70         Evas_Object *win;
71         Evas_Object *base;
72         Evas_Object *photo;
73         Evas_Object *photo_pre;
74
75         struct _viewer viewer;
76         struct _playlist playlist;
77         struct timeout_handler *timeout;
78         struct playermgr *player;
79         struct progressbar *progress;
80
81         bool bar_show;
82 };
83
84 struct _btn_info {
85         const char *name;
86         int loc;
87 };
88
89 static struct _btn_info btn_movie[] = {
90         {
91                 .name = SRC_BTN_PREV,
92                 .loc = 1,
93         },
94         {
95                 .name = SRC_BTN_PLAY,
96                 .loc = 2,
97         },
98         {
99                 .name = SRC_BTN_NEXT,
100                 .loc = 3,
101         },
102 };
103
104 static struct _btn_info btn_photo[] = {
105         {
106                 .name = SRC_BTN_GALLERY_PREV,
107                 .loc = 0,
108         },
109         {
110                 .name = SRC_BTN_GALLERY_NEXT,
111                 .loc = 4,
112         },
113 };
114
115 static struct _btn_info btn_video[] = {
116         {
117                 .name = SRC_BTN_GALLERY_PREV,
118                 .loc = 0,
119         },
120         {
121                 .name = SRC_BTN_PLAY,
122                 .loc = 2,
123         },
124         {
125                 .name = SRC_BTN_GALLERY_NEXT,
126                 .loc = 4,
127         },
128 };
129
130 struct _viewer_info {
131         struct _btn_info *btns;
132         int btn_count;
133         int focus_loc;
134         void (*callback)(void *, const char *);
135 };
136
137 static void _player_play(struct _priv *priv);
138 static void _player_stop(struct _priv *priv);
139
140 static void _callback_movie(void *data, const char *ev);
141 static void _callback_photo(void *data, const char *ev);
142 static void _callback_video(void *data, const char *ev);
143
144 static struct _viewer_info viewer_info[] = {
145         {
146                 .btns = btn_movie,
147                 .btn_count = 3,
148                 .focus_loc = 1,
149                 .callback = _callback_movie,
150         },
151         {
152                 .btns = btn_photo,
153                 .btn_count = 2,
154                 .focus_loc = 1,
155                 .callback = _callback_photo,
156         },
157         {
158                 .btns = btn_video,
159                 .btn_count = 3,
160                 .focus_loc = 2,
161                 .callback = _callback_video,
162         },
163 };
164
165 static void _add_to_recent(struct _priv *priv)
166 {
167         app_media *am;
168         app_media_info *mi;
169
170         am = eina_list_nth(priv->playlist.list, priv->playlist.cur);
171         if (!am) {
172                 _ERR("failed to get app_media");
173                 return;
174         }
175
176         mi = app_media_get_info(am);
177         if (!mi) {
178                 _ERR("failed to getting media info");
179                 return;
180         }
181
182         app_contents_recent_add(CONTENTS_MEDIA, mi->media_id);
183
184         app_media_update(am);
185 }
186
187 /*
188  * NOTE: Workaround
189  * we assumed that if video content have the copyright then it's a movie.
190  */
191 static inline bool _check_movie_type(app_media_info *mi)
192 {
193         return strcmp(mi->video->copyright, VIDEO_COPYRIGHT);
194 }
195
196 static void _set_bg_color(struct _priv *priv, int r, int g, int b, int a)
197 {
198         Evas_Object *bg;
199
200         bg = evas_object_rectangle_add(evas_object_evas_get(priv->base));
201         if (!bg) {
202                 _ERR("failed to add rect");
203                 return;
204         }
205
206         evas_object_color_set(bg, r, g, b, a);
207
208         elm_object_part_content_set(priv->base, PART_VIEWER_BG, bg);
209 }
210
211 static void _draw_thumbnail(struct _priv *priv, app_media_info *mi)
212 {
213         Evas_Object *obj;
214
215         if (priv->photo_pre) {
216                 evas_object_del(priv->photo_pre);
217                 priv->photo_pre = NULL;
218         }
219
220         if (priv->photo) {
221                 evas_object_del(priv->photo);
222                 priv->photo = NULL;
223         }
224
225         obj = elm_image_add(priv->base);
226         if (!obj) {
227                 _ERR("failed to adding image");
228                 return;
229         }
230
231         elm_image_file_set(obj, mi->thumbnail_path, NULL);
232         elm_object_part_content_set(priv->base, PART_VIEWER_CONTENT, obj);
233
234         priv->photo = obj;
235 }
236
237 static void _remove_thumbnail(struct _priv *priv)
238 {
239         if (priv->photo_pre) {
240                 evas_object_del(priv->photo_pre);
241                 priv->photo_pre = NULL;
242         }
243
244         if (priv->photo) {
245                 evas_object_del(priv->photo);
246                 priv->photo = NULL;
247         }
248
249         _set_bg_color(priv, 0, 0, 0, 0);
250
251         elm_object_part_content_unset(priv->base, PART_VIEWER_CONTENT);
252 }
253
254 static void _image_loaded(void *data, Evas_Object *obj, void *ev)
255 {
256         struct _priv *priv;
257
258         if (!data || !obj)
259                 return;
260
261         priv = data;
262
263         if (priv->photo != priv->photo_pre) {
264                 if (priv->photo)
265                         evas_object_del(priv->photo);
266
267                 priv->photo = obj;
268         }
269
270         elm_object_part_content_set(priv->base, PART_VIEWER_CONTENT, obj);
271 }
272
273 static void _image_loaded_detail(void *data, Evas_Object *obj, void *ev)
274 {
275         struct _priv *priv;
276
277         if (!data)
278                 return;
279
280         priv = data;
281
282         priv->photo_pre = NULL;
283
284         _add_to_recent(priv);
285 }
286
287 static void _draw_contents(struct _priv *priv, int id, app_media_info *mi)
288 {
289         Evas_Object *obj;
290
291         if (id == VIEWER_MOVIE) {
292                 _player_play(priv);
293                 return;
294         } else if (id == VIEWER_VIDEO) {
295                 _draw_thumbnail(priv, mi);
296                 return;
297         }
298
299         if (!mi->file_path)
300                 return;
301
302         if (priv->photo_pre) {
303                 obj = priv->photo_pre;
304         } else {
305                 obj = elm_photocam_add(priv->base);
306                 if (!obj) {
307                         _ERR("failed to adding photocam");
308                         return;
309                 }
310
311                 evas_object_smart_callback_add(obj, "loaded",
312                                 _image_loaded, priv);
313                 evas_object_smart_callback_add(obj, "loaded,detail",
314                                 _image_loaded_detail, priv);
315
316                 elm_object_focus_allow_set(obj, EINA_FALSE);
317                 elm_scroller_policy_set(obj,
318                                 ELM_SCROLLER_POLICY_AUTO,
319                                 ELM_SCROLLER_POLICY_AUTO);
320
321                 /*
322                  * set this photocam object to photo_pre (preloaded photo)
323                  * On "loaded" callback, photo_pre object will pass to photo
324                  * On "loaded,detail" callback photo_pre object will set to NULL
325                  */
326                 priv->photo_pre = obj;
327         }
328
329         _set_bg_color(priv, 0, 0, 0, 255);
330
331         elm_photocam_file_set(obj, mi->file_path);
332         elm_photocam_zoom_mode_set(obj, ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT);
333 }
334
335 static void _draw_title_bar(struct _priv *priv, int id, app_media_info *mi)
336 {
337         char buf[32] = {0,};
338         char day[32] = {0,};
339         char date[32] = {0,};
340
341         if (id == VIEWER_MOVIE) {
342                 elm_object_part_text_set(priv->base,
343                                 PART_VIEWER_TITLE, mi->title);
344
345                 elm_object_part_text_set(priv->base, PART_VIEWER_DATE, "");
346                 elm_object_part_text_set(priv->base, PART_VIEWER_PAGE, "");
347         } else {
348                 strftime(date, sizeof(date), "%d %b, %Y", mi->content_time);
349                 strftime(day, sizeof(day), "%a", mi->content_time);
350                 util_up_string(day);
351
352                 snprintf(buf, sizeof(buf), "%s, %s", day, date);
353
354                 elm_object_part_text_set(priv->base, PART_VIEWER_DATE, buf);
355
356                 snprintf(buf, sizeof(buf), "%d / %d", priv->playlist.cur + 1,
357                                 eina_list_count(priv->playlist.list));
358                 elm_object_part_text_set(priv->base, PART_VIEWER_PAGE, buf);
359
360                 elm_object_part_text_set(priv->base, PART_VIEWER_TITLE, "");
361         }
362 }
363
364 static void _draw_progressbar(struct _priv *priv, int id, app_media_info *mi)
365 {
366         if (id == VIEWER_PHOTO) {
367                 elm_object_part_text_set(priv->base, PART_VIEWER_PROGRESS, "");
368                 elm_object_part_text_set(priv->base, PART_VIEWER_TOTAL, "");
369                 progressbar_hide(priv->progress);
370
371                 return;
372         }
373
374         progressbar_reset(priv->progress,
375                         mi->video->position, mi->video->duration);
376         progressbar_show(priv->progress);
377 }
378
379 static void _draw_favorite_icon(struct _priv *priv, int id, app_media_info *mi)
380 {
381         if (mi->favorite)
382                 elm_object_signal_emit(priv->base, SIG_VIEWER_SHOW_FAV, "");
383         else
384                 elm_object_signal_emit(priv->base, SIG_VIEWER_HIDE_FAV, "");
385 }
386
387 static app_media_info *_get_current_media_info(struct _priv *priv)
388 {
389         app_media *am;
390         app_media_info *mi;
391
392         am = eina_list_nth(priv->playlist.list, priv->playlist.cur);
393         if (!am) {
394                 _ERR("failed to get app_media");
395                 return NULL;
396         }
397
398         mi = app_media_get_info(am);
399         if (!mi) {
400                 _ERR("failed to getting media info");
401                 return NULL;
402         }
403
404         return mi;
405 }
406
407 static void _set_played_position(struct _priv *priv, int position)
408 {
409         video_meta_h video;
410         app_media *am;
411         int r;
412
413         am = eina_list_nth(priv->playlist.list, priv->playlist.cur);
414         if (!am) {
415                 _ERR("failed to get app_media");
416                 return;
417         }
418
419         video = app_media_get_video_handle(am);
420         if (!video) {
421                 _ERR("failed to getting video handle");
422                 return;
423         }
424
425         r = video_meta_set_played_position(video, position);
426         if (r != MEDIA_CONTENT_ERROR_NONE) {
427                 _ERR("failed to set played position");
428                 return;
429         }
430
431         r = video_meta_update_to_db(video);
432         if (r != MEDIA_CONTENT_ERROR_NONE) {
433                 _ERR("failed to update db");
434                 return;
435         }
436
437         app_media_update(am);
438 }
439
440 static void _update_to_player(struct _priv *priv)
441 {
442         viewmgr_update_view(VIEW_MPLAYER, UPDATE_PLAYER, NULL);
443 }
444
445 static bool _viewer_show(struct _priv *priv)
446 {
447         struct _viewer_info *info;
448         struct controller *ctl;
449         int id;
450         int loc;
451         app_media_info *mi;
452
453         mi = _get_current_media_info(priv);
454         if (!mi) {
455                 _ERR("failed to getting media info");
456                 return false;
457         }
458
459         switch (mi->media_type) {
460         case MEDIA_CONTENT_TYPE_IMAGE:
461                 id = VIEWER_PHOTO;
462                 break;
463         case MEDIA_CONTENT_TYPE_VIDEO:
464                 if (_check_movie_type(mi))
465                         id = VIEWER_MOVIE;
466                 else
467                         id = VIEWER_VIDEO;
468                 break;
469         default:
470                 return false;
471         }
472
473         info = &viewer_info[id];
474         ctl = priv->viewer.ctl[id];
475         priv->viewer.cur = id;
476
477         ctl->ops->show(ctl->handle);
478
479         switch (priv->playlist.dir) {
480         case DIR_PREV:
481                 loc = 0;
482                 break;
483         case DIR_NEXT:
484                 loc = info->btn_count - 1;
485                 break;
486         case DIR_NONE:
487         default:
488                 loc = info->focus_loc;
489                 if (id == VIEWER_MOVIE) {
490                         ctl->ops->signal(ctl->handle,
491                                         PLAY_BTN_LOC, SIG_SET_PAUSE);
492                 }
493                 break;
494         }
495         ctl->ops->signal(ctl->handle, loc, SIG_SET_FOCUS);
496         ctl->ops->focus(ctl->handle, loc, true);
497
498         _draw_title_bar(priv, id, mi);
499         _draw_progressbar(priv, id, mi);
500         _draw_favorite_icon(priv, id, mi);
501
502         _draw_contents(priv, id, mi);
503
504         return true;
505 }
506
507 static void _viewer_hide(struct _priv *priv)
508 {
509         struct controller *ctl;
510
511         ctl = priv->viewer.ctl[priv->viewer.cur];
512         ctl->ops->hide(ctl->handle);
513
514         elm_object_signal_emit(priv->base, SIG_VIEWER_HIDE_FAV, "");
515 }
516
517 static bool _viewer_add(struct _priv *priv, int id)
518 {
519         struct _viewer_info *info;
520         struct controller *ctl;
521         int i;
522
523         info = &viewer_info[id];
524
525         ctl = controller_create(priv->base);
526         if (!ctl) {
527                 _ERR("failed to create controller");
528                 return false;
529         }
530
531         for (i = 0; i < info->btn_count; i++) {
532                 ctl->ops->add_control(ctl->handle,
533                                 info->btns[i].name, info->btns[i].loc,
534                                 STYLE_VIEWER_BTN, PART_VIEWER_BTN);
535         }
536
537         ctl->ops->add_callback(ctl->handle, info->callback, priv);
538
539         priv->viewer.ctl[id] = ctl;
540
541         return true;
542 }
543
544 static void _viewer_delete(struct _priv *priv)
545 {
546         int i;
547
548         for (i = 0; i < VIEWER_MAX; i++)
549                 controller_destroy(priv->viewer.ctl[i]);
550
551         progressbar_destroy(priv->progress);
552 }
553
554 static bool _viewer_prev(struct _priv *priv)
555 {
556         int total;
557         bool r;
558         struct controller *ctl;
559
560         ctl = priv->viewer.ctl[priv->viewer.cur];
561         ctl->ops->signal(ctl->handle, 0, SIG_SET_UNFOCUS);
562
563         _viewer_hide(priv);
564
565         total = eina_list_count(priv->playlist.list);
566
567         if (priv->playlist.cur == 0)
568                 priv->playlist.cur = total - 1;
569         else
570                 priv->playlist.cur--;
571
572         priv->playlist.dir = DIR_PREV;
573
574         r = _viewer_show(priv);
575
576         return r;
577 }
578
579 static bool _viewer_next(struct _priv *priv)
580 {
581         int total;
582         bool r;
583         struct controller *ctl;
584
585         ctl = priv->viewer.ctl[priv->viewer.cur];
586         ctl->ops->signal(ctl->handle, ctl->ops->get_count(ctl->handle) - 1,
587                         SIG_SET_UNFOCUS);
588
589         _viewer_hide(priv);
590
591         total = eina_list_count(priv->playlist.list);
592
593         if (priv->playlist.cur == total - 1)
594                 priv->playlist.cur = 0;
595         else
596                 priv->playlist.cur++;
597
598         priv->playlist.dir = DIR_NEXT;
599
600         r = _viewer_show(priv);
601
602         return r;
603 }
604
605 static void _show_bar(struct _priv *priv)
606 {
607         struct controller *ctl;
608
609         if (priv->bar_show)
610                 return;
611
612         elm_object_signal_emit(priv->base, SIG_SHOW_BAR, "");
613         priv->bar_show = true;
614
615         ctl = priv->viewer.ctl[priv->viewer.cur];
616         ctl->ops->enable(ctl->handle);
617 }
618
619 static void _hide_bar(struct _priv *priv)
620 {
621         struct controller *ctl;
622
623         if (!priv->bar_show)
624                 return;
625
626         elm_object_signal_emit(priv->base, SIG_HIDE_BAR, "");
627         priv->bar_show = false;
628
629         ctl = priv->viewer.ctl[priv->viewer.cur];
630         ctl->ops->disable(ctl->handle);
631 }
632
633 static void _pop_view(struct _priv *priv)
634 {
635         struct view_update_data vdata;
636
637         if (priv->viewer.cur == VIEWER_MOVIE ||
638                         priv->viewer.cur == VIEWER_VIDEO)
639                 _player_stop(priv);
640
641         if (viewmgr_active_view_count() > 1) {
642                 vdata.index = priv->playlist.cur;
643                 viewmgr_update_view(VIEW_BASE, UPDATE_FOCUS, &vdata);
644         }
645
646         viewmgr_pop_view();
647
648         if (viewmgr_active_view_count() == 0)
649                 ui_app_exit();
650 }
651
652 static void _timeout_cb(void *data, int type, void *ei)
653 {
654         _hide_bar(data);
655 }
656
657 static void _event_cb(void *data, int type, void *ei)
658 {
659         struct _priv *priv;
660
661         if (!data)
662                 return;
663
664         priv = data;
665
666         if (type == ECORE_EVENT_KEY_UP) {
667                 Evas_Event_Key_Up *ev;
668
669                 if (!ei)
670                         return;
671
672                 ev = ei;
673
674                 if (!strcmp(ev->keyname, KEY_BACK) ||
675                                 !strcmp(ev->keyname, KEY_BACK_REMOTE)) {
676                         if (priv->bar_show) {
677                                 _pop_view(priv);
678                                 return;
679                         }
680                 }
681         }
682
683         _show_bar(data);
684 }
685
686 static int _player_get_position(void *data)
687 {
688         struct _priv *priv;
689
690         if (!data)
691                 return 0;
692
693         priv = data;
694
695         return playermgr_get_position(priv->player);
696 }
697
698 static void _player_play(struct _priv *priv)
699 {
700         app_media_info *mi;
701         player_state_e state;
702
703         playermgr_get_state(priv->player, &state);
704
705         switch (state) {
706         case PLAYER_STATE_PAUSED:
707                 progressbar_resume(priv->progress);
708                 playermgr_resume(priv->player);
709                 break;
710         case PLAYER_STATE_PLAYING:
711                 progressbar_pause(priv->progress);
712                 playermgr_pause(priv->player);
713                 break;
714         case PLAYER_STATE_IDLE:
715         case PLAYER_STATE_READY:
716                 mi = _get_current_media_info(priv);
717                 if (!mi) {
718                         _ERR("failed to getting media info");
719                         return;
720                 }
721
722                 _remove_thumbnail(priv);
723                 _update_to_player(priv);
724
725                 progressbar_start(priv->progress);
726                 playermgr_play(priv->player, mi->file_path,
727                                 mi->video->position);
728
729                 _add_to_recent(priv);
730
731                 break;
732         default:
733                 _ERR("player was not created");
734                 break;
735         }
736 }
737
738 static void _player_stop(struct _priv *priv)
739 {
740         struct controller *ctl;
741         int position;
742
743         if (priv->viewer.cur == VIEWER_MOVIE) {
744                 position = playermgr_get_position(priv->player);
745                 _set_played_position(priv, position);
746         }
747
748         progressbar_stop(priv->progress);
749         playermgr_stop(priv->player);
750
751         ctl = priv->viewer.ctl[priv->viewer.cur];
752         ctl->ops->signal(ctl->handle, PLAY_BTN_LOC, SIG_SET_PLAY);
753 }
754
755 static void _player_complete_cb(void *data)
756 {
757         struct _priv *priv;
758
759         if (!data)
760                 return;
761
762         priv = data;
763
764         _set_played_position(priv, 0);
765         _player_stop(priv);
766
767         if (priv->viewer.cur == VIEWER_MOVIE)
768                 _pop_view(priv);
769         else if (priv->viewer.cur == VIEWER_VIDEO) {
770                 _viewer_show(priv);
771                 _show_bar(data);
772         }
773 }
774
775 static struct progressbar_ops _progressbar_ops = {
776         .get_value = _player_get_position,
777 };
778
779 static void _callback_movie(void *data, const char *ev)
780 {
781         struct _priv *priv;
782         int ms;
783
784         if (!data || !ev)
785                 return;
786
787         priv = data;
788
789         if (!strcmp(ev, SRC_BTN_PREV)) {
790                 playermgr_set_position(priv->player, 0, NULL, NULL);
791         } else if (!strcmp(ev, SRC_BTN_NEXT)) {
792                 ms = playermgr_get_duration(priv->player);
793                 playermgr_set_position(priv->player, ms - 500, NULL, NULL);
794         } else if (!strcmp(ev, SRC_BTN_PLAY)) {
795                 _player_play(priv);
796         }
797 }
798
799 static void _callback_photo(void *data, const char *ev)
800 {
801         struct _priv *priv;
802
803         if (!data || !ev)
804                 return;
805
806         priv = data;
807
808         if (!strcmp(ev, SRC_BTN_GALLERY_PREV))
809                 _viewer_prev(priv);
810         else if (!strcmp(ev, SRC_BTN_GALLERY_NEXT))
811                 _viewer_next(priv);
812 }
813
814 static void _callback_video(void *data, const char *ev)
815 {
816         struct _priv *priv;
817
818         if (!data || !ev)
819                 return;
820
821         priv = data;
822
823         if (!strcmp(ev, SRC_BTN_GALLERY_PREV)) {
824                 _player_stop(priv);
825                 _viewer_prev(priv);
826         } else if (!strcmp(ev, SRC_BTN_GALLERY_NEXT)) {
827                 _player_stop(priv);
828                 _viewer_next(priv);
829         } else if (!strcmp(ev, SRC_BTN_PLAY)) {
830                 _player_play(priv);
831         }
832 }
833
834 static bool _ui_init(struct _priv *priv)
835 {
836         struct progressbar *prog;
837         bool r;
838         int i;
839
840         for (i = 0; i < VIEWER_MAX; i++) {
841                 r = _viewer_add(priv, i);
842                 if (!r)
843                         goto err;
844         }
845
846         prog = progressbar_create(priv->base, STYLE_VIEWER_PROGRESS);
847         if (!prog) {
848                 _ERR("failed to adding progressbar");
849                 goto err;
850         }
851
852         progressbar_set_parts(prog, PART_VIEWER_SLIDER, PART_VIEWER_TOTAL,
853                         PART_VIEWER_PROGRESS, VIEWER_SEPARATOR);
854         progressbar_set_time_format(prog, PROG_TIME_FORMAT_FULL);
855         progressbar_set_ops(prog, &_progressbar_ops, priv);
856
857         priv->progress = prog;
858
859         priv->timeout = timeout_handler_init(VIEWER_TIMEOUT,
860                         _timeout_cb, priv,
861                         _event_cb, priv);
862
863         priv->bar_show = true;
864
865         return true;
866
867 err:
868         _viewer_delete(priv);
869         return false;
870 }
871
872 static Evas_Object *_create(Evas_Object *win, void *data)
873 {
874         struct _priv *priv;
875         Evas_Object *base;
876         struct playermgr *player;
877         bool r;
878
879         if (!win) {
880                 _ERR("failed to get win object");
881                 return NULL;
882         }
883
884         priv = calloc(1, sizeof(*priv));
885         if (!priv) {
886                 _ERR("failed to allocate priv");
887                 return NULL;
888         }
889
890         base = elm_layout_add(win);
891         if (!base) {
892                 _ERR("failed to create base object");
893                 free(priv);
894                 return NULL;
895         }
896
897         elm_layout_file_set(base, EDJEFILE, GRP_VIEWER_VIEW);
898
899         evas_object_size_hint_weight_set(base,
900                         EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
901         elm_win_resize_object_add(win, base);
902
903         priv->win = win;
904         priv->base = base;
905
906         priv->playlist.list = NULL;
907         priv->playlist.cur = 0;
908         priv->playlist.dir = DIR_NONE;
909
910         player = playermgr_create(win);
911         if (!player) {
912                 _ERR("failed to create player");
913                 return NULL;
914         }
915
916         r = playermgr_set_completed_cb(player, _player_complete_cb, priv);
917         if (!r) {
918                 _ERR("failed to set callback");
919                 playermgr_destroy(player);
920                 return NULL;
921         }
922
923         priv->player = player;
924
925         r = _ui_init(priv);
926         if (!r) {
927                 _ERR("failed to init UI");
928                 playermgr_destroy(player);
929                 return NULL;
930         }
931
932         viewmgr_set_view_data(VIEW_VIEWER, priv);
933
934         return base;
935 }
936
937 static void _show(void *view_data)
938 {
939         struct _priv *priv;
940
941         if (!view_data) {
942                 _ERR("failed to get view data");
943                 return;
944         }
945
946         priv = view_data;
947
948         media_content_connect();
949
950         _viewer_show(priv);
951
952         timeout_handler_enable(priv->timeout, true);
953
954         evas_object_show(priv->base);
955 }
956
957 static void _hide(void *view_data)
958 {
959         struct _priv *priv;
960
961         if (!view_data) {
962                 _ERR("failed to get view data");
963                 return;
964         }
965
966         priv = view_data;
967
968         _viewer_hide(priv);
969
970         timeout_handler_enable(priv->timeout, false);
971
972         media_content_disconnect();
973
974         evas_object_hide(priv->base);
975 }
976
977 static void _update(void *view_data, int update_type, void *data)
978 {
979         struct _priv *priv;
980         struct view_update_data *vdata;
981
982         if (!view_data) {
983                 _ERR("failed to get view data");
984                 return;
985         }
986
987         priv = view_data;
988         vdata = data;
989
990         switch (update_type) {
991         case UPDATE_CONTENT:
992                 if (!vdata)
993                         break;
994
995                 priv->playlist.list = vdata->list;
996                 priv->playlist.cur = vdata->index;
997                 priv->playlist.dir = DIR_NONE;
998                 break;
999         default:
1000                 break;
1001         }
1002 }
1003
1004 static void _pause(void *view_data)
1005 {
1006         struct _priv *priv;
1007
1008         if (!view_data) {
1009                 _ERR("failed to get view data");
1010                 return;
1011         }
1012
1013         priv = view_data;
1014
1015         _pop_view(priv);
1016 }
1017
1018 static void _destroy(void *view_data)
1019 {
1020         struct _priv *priv;
1021
1022         if (!view_data) {
1023                 _ERR("failed to get view data");
1024                 return;
1025         }
1026
1027         priv = view_data;
1028
1029         _viewer_delete(priv);
1030
1031         timeout_handler_fini(priv->timeout);
1032
1033         playermgr_destroy(priv->player);
1034
1035         evas_object_del(priv->base);
1036
1037         free(priv);
1038 }
1039
1040 static view_class _vclass = {
1041         .view_id = VIEW_VIEWER,
1042         .create = _create,
1043         .show = _show,
1044         .hide = _hide,
1045         .update = _update,
1046         .pause = _pause,
1047         .destroy = _destroy,
1048 };
1049
1050 view_class *view_viewer_get_vclass(void)
1051 {
1052         return &_vclass;
1053 }