base: find the item to be focused using media id
[profile/tv/apps/native/air_mediahub.git] / src / layout / music.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 "view.h"
29 #include "data/mediadata.h"
30 #include "util/listmgr.h"
31 #include "util/util.h"
32
33 #define LIST_MEDIA_COND "media_type=3"
34
35 #define TEXT_NOCONTENT "No Music"
36 #define TEXT_NOW_PLAYING "Now Playing"
37
38 #define GRID_PADDING 26
39 #define GRID_ITEM_X (488 + GRID_PADDING)
40 #define GRID_ITEM_Y (134 + GRID_PADDING)
41 #define GRID_NUM_ITEM 4
42
43 #define BOX_PADDING (62 - GRID_PADDING)
44
45 struct _priv {
46         Evas_Object *base;
47         Evas_Object *layout;
48         Evas_Object *menu_btn;
49
50         layoutmgr *lmgr;
51
52         struct listmgr *listmgr;
53         struct listmgr_data *ldata;
54
55         struct mediadata *md;
56
57         Eina_List *media_list;
58
59         app_media *playing_info;
60 };
61
62 static char *_grid_text_get(void *data, Evas_Object *obj, const char *part)
63 {
64         app_media *am;
65         app_media_info *info;
66
67         if (!data)
68                 return NULL;
69
70         am = data;
71         info = app_media_get_info(am);
72         if (!info) {
73                 _ERR("failed to get media info");
74                 return NULL;
75         }
76
77         if (!strcmp(part, PART_ELM_TEXT_TITLE))
78                 return strdup(info->title);
79         else if (!strcmp(part, PART_ELM_TEXT_ARTIST))
80                 return strdup(info->audio->artist);
81         else if (!strcmp(part, PART_ELM_TEXT_ALBUM))
82                 return strdup(info->audio->album);
83
84         return NULL;
85 }
86
87 static Evas_Object *_grid_content_get(void *data,
88                         Evas_Object *obj, const char *part)
89 {
90         Evas_Object *image;
91         app_media *am;
92         app_media_info *info;
93
94         if (!data)
95                 return NULL;
96
97         am = data;
98         info = app_media_get_info(am);
99         if (!info) {
100                 _ERR("failed to get media info");
101                 return NULL;
102         }
103
104         image = NULL;
105         if (!strcmp(part, PART_ELM_SWALLOW_THUMBNAIL)) {
106                 image = util_add_image(obj, info->thumbnail_path);
107                 if (!image) {
108                         _ERR("failed to create image object");
109                         return NULL;
110                 }
111
112                 evas_object_show(image);
113         } else if (!strcmp(part, PART_ELM_SWALLOW_FAVORITE)) {
114                 if (!info->favorite)
115                         return NULL;
116
117                 image = util_add_image(obj, IMAGE_THUMBNAIL_FAVORITE);
118                 if (!image) {
119                         _ERR("failed to create image object");
120                         return NULL;
121                 }
122
123                 evas_object_show(image);
124         }
125
126         return image;
127 }
128
129 static struct grid_class _gclass = {
130         .item_style = STYLE_GRID_SONG_ITEM,
131         .text_get = _grid_text_get,
132         .content_get = _grid_content_get
133 };
134
135 static bool _update_playing_info(void *data, Evas_Object *base)
136 {
137         Evas_Object *content, *image;
138         app_media_info *info;
139         struct _priv *priv;
140
141         if (!data || !base) {
142                 _ERR("invalid argument");
143                 return false;
144         }
145
146         priv = data;
147
148         content = elm_object_part_content_get(base, PART_ITEM_CONTENT);
149         if (!content) {
150                 _ERR("failed to get content part");
151                 return false;
152         }
153
154         image = elm_object_part_content_get(content,
155                                 PART_PLAYING_CONTENT_THUMBNAIL);
156         if (!image) {
157                 _ERR("failed to get image object");
158                 return false;
159         }
160
161         info = app_media_get_info(priv->playing_info);
162         if (!info) {
163                 _ERR("failed to get app media info");
164                 return false;
165         }
166
167         elm_image_file_set(image, info->thumbnail_path, NULL);
168         elm_image_aspect_fixed_set(image, EINA_FALSE);
169
170         elm_object_part_text_set(content, PART_PLAYING_CONTENT_TITLE,
171                                 info->title);
172
173         elm_object_part_text_set(content, PART_PLAYING_CONTENT_ARTIST,
174                                 info->audio->artist);
175         elm_object_part_text_set(content, PART_PLAYING_CONTENT_ALBUM,
176                                 info->audio->album);
177
178         if (info->favorite)
179                 elm_object_signal_emit(content, SIG_PLAYING_SHOW_FAV,
180                                         SIG_SOURCE_SRC);
181         else
182                 elm_object_signal_emit(content, SIG_PLAYING_HIDE_FAV,
183                                         SIG_SOURCE_SRC);
184
185         return true;
186 }
187
188 static bool _draw_playing_title(Evas_Object *base)
189 {
190         Evas_Object *btn;
191
192         btn = elm_button_add(base);
193         if (!btn) {
194                 _ERR("failed to create button object");
195                 return false;
196         }
197
198         elm_object_style_set(btn, STYLE_BTN_INDEX);
199         elm_object_text_set(btn, TEXT_NOW_PLAYING);
200
201         elm_object_part_content_set(base, PART_ITEM_TITLE, btn);
202
203         return true;
204 }
205
206 static bool _draw_playing_content(Evas_Object *base)
207 {
208         Evas_Object *btn, *image;
209
210         btn = elm_button_add(base);
211         if (!btn) {
212                 _ERR("failed to create button object");
213                 return false;
214         }
215
216         elm_object_style_set(btn, STYLE_BTN_PLAYING_CONTENT);
217
218         image = elm_image_add(btn);
219         if (!image) {
220                 _ERR("failed to create image object");
221                 return false;
222         }
223
224         elm_object_part_content_set(btn, PART_PLAYING_CONTENT_THUMBNAIL, image);
225
226         elm_object_part_content_set(base, PART_ITEM_CONTENT, btn);
227
228         return true;
229 }
230
231 static bool _draw_playing_info(void *data, Evas_Object *base)
232 {
233         if (!base) {
234                 _ERR("invalid argument");
235                 return false;
236         }
237
238         if (!_draw_playing_title(base)) {
239                 _ERR("failed to draw playing title");
240                 return false;
241         }
242
243         if (!_draw_playing_content(base)) {
244                 _ERR("failed to draw playing content");
245                 return false;
246         }
247
248         return true;
249 }
250
251 static void _recent_item_selected(struct _priv *priv, app_media *am)
252 {
253         app_media_info *info;
254         struct view_update_data vdata;
255
256         info = app_media_get_info(am);
257         if (!info) {
258                 _ERR("failed to get app media info");
259                 return;
260         }
261
262         vdata.list = mediadata_get_medialist(priv->md);
263         vdata.index = util_get_media_index_from_id(vdata.list, info->media_id);
264
265         viewmgr_update_view(VIEW_MPLAYER, UPDATE_CONTENT, &vdata);
266         viewmgr_push_view(VIEW_MPLAYER);
267 }
268
269 static void _item_selected(struct _priv *priv, app_media *am)
270 {
271         struct view_update_data vdata;
272
273         vdata.list = mediadata_get_medialist(priv->md);
274         vdata.index = util_get_media_index(vdata.list, am);
275
276         viewmgr_update_view(VIEW_MPLAYER, UPDATE_CONTENT, &vdata);
277         viewmgr_push_view(VIEW_MPLAYER);
278 }
279
280 static void _playing_selected_cb(void *data, Evas_Object *obj)
281 {
282         struct _priv *priv;
283
284         if (!data || !obj)
285                 return;
286
287         priv = data;
288
289         _item_selected(priv, priv->playing_info);
290 }
291
292 static void _grid_selected_cb(void *data, Elm_Object_Item *it)
293 {
294         app_media *am;
295         struct _priv *priv;
296
297         if (!data || !it) {
298                 _ERR("invalid argument");
299                 return;
300         }
301
302         priv = data;
303
304         am = elm_object_item_data_get(it);
305         if (!am) {
306                 _ERR("failed to get app media");
307                 return;
308         }
309
310         _item_selected(priv, am);
311 }
312
313 static void _grid_key_down_cb(void *data, Elm_Object_Item *it,
314                         Evas_Event_Key_Down *ev)
315 {
316         app_media *am;
317         struct view_update_data vdata;
318         struct _priv *priv;
319
320         if (!data || !ev) {
321                 _ERR("invalid argument");
322                 return;
323         }
324
325         priv = data;
326
327         if (!strcmp(ev->keyname, KEY_MENU) ||
328                 !strcmp(ev->keyname, KEY_MENU_REMOTE)) {
329                 am = elm_object_item_data_get(it);
330                 if (!am) {
331                         _ERR("failed to get app media");
332                         return;
333                 }
334
335                 vdata.list = mediadata_get_medialist(priv->md);
336                 vdata.index = util_get_media_index(vdata.list, am);
337
338                 viewmgr_update_view(VIEW_ACTION_MENU, UPDATE_CONTENT, &vdata);
339                 viewmgr_show_view(VIEW_ACTION_MENU);
340         }
341 }
342
343 static struct listmgr_data *_create_listmgr_data(struct _priv *priv)
344 {
345         struct listmgr_data *data;
346         struct play_info_ops *pops;
347         struct grid_ops *gops;
348
349         data = calloc(1, sizeof(*data));
350         if (!data)
351                 goto err;
352
353         data->menu_btn = priv->menu_btn;
354
355         data->grid_item_x = GRID_ITEM_X;
356         data->grid_item_y = GRID_ITEM_Y;
357         data->grid_num_item = GRID_NUM_ITEM;
358         data->box_padding = BOX_PADDING;
359
360         pops = calloc(1, sizeof(*pops));
361         if (!pops)
362                 goto err2;
363
364         pops->draw = _draw_playing_info;
365         pops->update = _update_playing_info;
366         pops->selected_cb = _playing_selected_cb;
367         pops->ops_data = priv;
368
369         gops = calloc(1, sizeof(*gops));
370         if (!gops)
371                 goto err3;
372
373         gops->gclass = &_gclass;
374         gops->key_down_cb = _grid_key_down_cb;
375         gops->selected_cb = _grid_selected_cb;
376         gops->ops_data = priv;
377
378         data->pops = pops;
379         data->gops = gops;
380
381         return data;
382
383 err3:
384         free(pops);
385 err2:
386         free(data);
387 err:
388         _ERR("failed to allocate memory");
389         return NULL;
390 }
391
392 static void _update_content_info(struct _priv *priv)
393 {
394         int count;
395         char buf[128];
396
397         count = mediadata_get_media_count(priv->md, E_MEDIA_MUSIC);
398         if (count < 0) {
399                 _ERR("failed to get media count");
400                 return;
401         }
402
403         snprintf(buf, sizeof(buf), "%d Songs", count);
404
405         elm_object_part_text_set(priv->layout, PART_CONTENT_INFO, buf);
406 }
407
408 static void _update_content_list(struct _priv *priv)
409 {
410         Eina_List *list;
411
412         if (priv->media_list)
413                 return;
414
415         list = mediadata_get_list(priv->md, E_LIST_NAME);
416         if (!list) {
417                 elm_object_part_text_set(priv->layout,
418                                 PART_NOCONTENT, TEXT_NOCONTENT);
419                 return;
420         }
421
422         if (!listmgr_update_content_list(priv->listmgr, list))
423                 _ERR("failed to update list area");
424
425         priv->media_list = list;
426
427         _update_content_info(priv);
428 }
429
430 static app_media *_get_playing_item(Eina_List *list)
431 {
432         GList *rlist;
433         app_media *am;
434         struct recent_data *rdata;
435         int r;
436
437         rlist = NULL;
438         am = NULL;
439         r = app_contents_get_recent_list(CONTENTS_MUSIC, 1, &rlist);
440         if (r != APP_CONTENTS_ERROR_NONE) {
441                 _ERR("failed to get movie recent list");
442                 return NULL;
443         }
444
445         rdata = g_list_nth_data(rlist, 0);
446         if (rdata && rdata->id)
447                 am = util_find_media_info(list, rdata->id);
448
449         app_contents_free_recent_list(rlist);
450
451         return am;
452 }
453
454 static void _update_playing_item(struct _priv *priv, const char *id)
455 {
456         Eina_List *list;
457         app_media *am;
458         app_media_info *info;
459
460         list = mediadata_get_medialist(priv->md);
461         if (id)
462                 am = util_find_media_info(list, id);
463         else
464                 am = _get_playing_item(list);
465
466         if (!am) {
467                 _ERR("failed to get app media");
468                 return;
469         }
470
471         info = app_media_get_info(am);
472         if (!info) {
473                 _ERR("failed to get app media info");
474                 return;
475         }
476
477         priv->playing_info = am;
478
479         if (!listmgr_update_play_info(priv->listmgr, info))
480                 _ERR("failed to update now playing item");
481 }
482
483 static bool _create(layoutmgr *lmgr, void *data)
484 {
485         struct listmgr *listmgr;
486         struct listmgr_data *ldata;
487         struct mediadata *md;
488         struct _priv *priv;
489         Evas_Object *base, *layout;
490
491         if (!lmgr) {
492                 _ERR("failed to get layoutmgr");
493                 return false;
494         }
495
496         if (!data) {
497                 _ERR("invalid argument");
498                 return false;
499         }
500
501         priv = calloc(1, sizeof(*priv));
502         if (!priv) {
503                 _ERR("failed to allocate priv");
504                 return false;
505         }
506
507         priv->menu_btn = (Evas_Object *)data;
508
509         base = layoutmgr_get_base(lmgr);
510         if (!base) {
511                 _ERR("failed to get base object");
512                 goto err;
513         }
514
515         layout = elm_layout_add(base);
516         if (!layout) {
517                 _ERR("failed to create layout");
518                 goto err;
519         }
520
521         if (!elm_layout_file_set(layout, EDJEFILE, GRP_MUSIC_LAYOUT)) {
522                 _ERR("failed to set layout file");
523                 goto err2;
524         }
525
526         ldata = _create_listmgr_data(priv);
527         if (!ldata) {
528                 _ERR("failed to create listmgr data");
529                 goto err2;
530         }
531
532         listmgr = listmgr_create(layout, (void *)ldata);
533         if (!listmgr) {
534                 _ERR("failed to create listmgr");
535                 goto err3;
536         }
537
538         md = mediadata_create(LIST_MEDIA_COND, E_SOURCE_ALL, E_SORT_NAME);
539         if (!md) {
540                 _ERR("failed to create mediadata");
541                 listmgr_destroy(listmgr);
542                 goto err3;
543         }
544
545         priv->base = base;
546         priv->layout = layout;
547         priv->lmgr = lmgr;
548         priv->listmgr = listmgr;
549         priv->ldata = ldata;
550         priv->md = md;
551
552         layoutmgr_set_layout_data(lmgr, LAYOUT_MUSIC, priv);
553
554         if (!listmgr_draw_list_area(listmgr)) {
555                 _ERR("failed to draw list area");
556                 mediadata_destroy(md);
557                 listmgr_destroy(listmgr);
558                 goto err3;
559         }
560
561         return true;
562
563 err3:
564         free(ldata);
565 err2:
566         evas_object_del(layout);
567 err:
568         free(priv);
569         return false;
570 }
571
572 static void _destroy(void *layout_data)
573 {
574         struct _priv *priv;
575
576         if (!layout_data) {
577                 _ERR("failed to get layout data");
578                 return;
579         }
580
581         priv = layout_data;
582
583         mediadata_free_list(priv->media_list);
584         mediadata_destroy(priv->md);
585
586         listmgr_destroy(priv->listmgr);
587         free(priv->ldata->gops);
588         free(priv->ldata);
589
590         evas_object_del(priv->layout);
591
592         free(priv);
593 }
594
595 static void _show(void *layout_data)
596 {
597         struct _priv *priv;
598
599         if (!layout_data) {
600                 _ERR("failed to layout data");
601                 return;
602         }
603
604         priv = layout_data;
605
606         evas_object_show(priv->layout);
607         elm_object_part_content_set(priv->base,
608                         PART_THUMBNAIL_AREA, priv->layout);
609 }
610
611 static void _hide(void *layout_data)
612 {
613         struct _priv *priv;
614
615         if (!layout_data) {
616                 _ERR("failed to get layout data");
617                 return;
618         }
619
620         priv = layout_data;
621
622         evas_object_hide(priv->layout);
623         elm_object_part_content_unset(priv->base, PART_THUMBNAIL_AREA);
624 }
625
626 static void _update(void *layout_data, int update_type, void *data)
627 {
628         struct view_update_data *vdata;
629         struct _priv *priv;
630
631         if (!layout_data) {
632                 _ERR("failed to get layout data");
633                 return;
634         }
635
636         priv = layout_data;
637
638         switch (update_type) {
639         case UPDATE_CONTENT:
640                 _update_content_list(priv);
641                 _update_playing_item(priv, NULL);
642                 break;
643         case UPDATE_CONTENT_ITEM:
644                 listmgr_update_content_item(priv->listmgr);
645                 _update_playing_item(priv, NULL);
646                 break;
647         case UPDATE_PLAY_INFO:
648                 if (!data) {
649                         _ERR("invalid argument");
650                         return;
651                 }
652
653                 vdata = data;
654
655                 _update_playing_item(priv, vdata->id);
656                 break;
657         case UPDATE_FOCUS:
658                 listmgr_focus_play_info(priv->listmgr);
659                 break;
660         case UPDATE_RECENT:
661                 if (!data) {
662                         _ERR("invalid argument");
663                         return;
664                 }
665
666                 _update_content_list(priv);
667                 _recent_item_selected(priv, data);
668                 break;
669         case UPDATE_FOCUS_STATE:
670                 listmgr_set_focus_state(priv->listmgr, EINA_FALSE);
671                 break;
672         default:
673                 break;
674         }
675 }
676
677 static layout_class _lclass = {
678         .layout_id = LAYOUT_MUSIC,
679         .create = _create,
680         .show = _show,
681         .hide = _hide,
682         .destroy = _destroy,
683         .update = _update,
684 };
685
686 layout_class *layout_music_get_lclass(void)
687 {
688         return &_lclass;
689 }