11e40f756825639fed2b1720a6428de913598ef9
[profile/tv/apps/native/musicplayer.git] / src / views / album-layout.cpp
1 /*
2  * Copyright (c) 2014 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 <Eina.h>
19 #include <utilX.h>
20 #include <AppCommon.h>
21 #include <InputHandler.h>
22 #include <SortMgr.h>
23 #include <Sort.h>
24 #include "dbg.h"
25 #include "i18n.h"
26 #include "define.h"
27 #include "album_info.h"
28 #include "song_info.h"
29 #include "music-controller.h"
30 #include "LayoutMgr.h"
31 #include "common.h"
32 #include "common-ui.h"
33 #include "BaseView.h"
34 #include "BaseLayout.h"
35 #include "ExtBaseLayout.h"
36 #include "ViewMgr.h"
37 #include "album-layout.h"
38 #include "album-songs-layout.h"
39 #include "base-view.h"
40
41 #define GENGRID_ITEM_SIZE_W (263+20)
42 #define GENGRID_ITEM_SIZE_H (359+20)
43
44
45 enum EObjectType {
46         ALBUM_LAYOUT,
47         ALBUM_GENGRID,
48 };
49
50 struct SAlbumItemInfo {
51         CAlbumInfo *alinfo;
52         Elm_Object_Item *item;
53 };
54
55 struct SCallback {
56         void(*cbHandleEmptyStatus)(void *cookie, bool emptyStatus);
57         void *cookie;
58 };
59
60 struct SAlbumLayout {
61         Evas_Object *win;
62         Evas_Object *base;
63         Evas_Object *grid;
64         Elm_Object_Item *focused_item;
65         Eina_List *alblist;
66         Eina_List *it_infolist;
67         Elm_Gengrid_Item_Class *item_class;
68         CMusicController *mhandle;
69         CLayoutMgr *lmgr;
70         CViewMgr *vmgr;
71         SContentInfo *ctxtinfo;
72         char *album_id;
73         CAlbumSongsLayout *layoutAlbumSongs;
74         SCallback callback;
75         CAlbumLayout* parent;
76
77         SAlbumLayout() {
78                 memset(this, 0, sizeof(SAlbumLayout));
79         }
80         
81         ~SAlbumLayout() {
82         }
83 };
84
85
86 char *CAlbumLayout::sm_CbGetGridItemText(void *data, Evas_Object *obj, const char *part)
87 {
88         SAlbumItemInfo *itinfo = (SAlbumItemInfo *)data;
89         CAlbumInfo *alinfo = NULL;
90         char *txt = NULL;
91
92         if (!itinfo || !obj)
93                 return NULL;
94
95         alinfo = itinfo->alinfo;
96         txt = NULL;
97
98         if (!strcmp(part, "elm.text"))
99                 txt = alinfo->Name();
100         else if (!strcmp(part, "elm.text1"))
101                 txt = alinfo->Artist();
102
103         if (txt)
104                 return strdup(txt);
105
106         return NULL;
107 }
108
109
110 Evas_Object *CAlbumLayout::sm_CbGetGridItemContent(void *data, Evas_Object *obj, const char *part)
111 {
112         SAlbumItemInfo *itinfo = (SAlbumItemInfo *)data;
113         CAlbumInfo *alinfo = NULL;
114         char *path = NULL;
115         Evas_Object *img = NULL;
116         char buf[MAX_LENGTH];
117
118         if (!itinfo || !obj)
119                 return NULL;
120
121         alinfo = itinfo->alinfo;
122
123         if (!strcmp(part, "elm.swallow.icon")) {
124                 img = elm_image_add(obj);
125                 if (!img)
126                         return NULL;
127
128                 path = alinfo->ThumbnailPath();
129                 if (!path) {
130                         snprintf(buf, sizeof(buf), "%s/%s", IMAGEDIR,
131                                 MUSIC_IMAGE_DEFAULT_THUMB_126);
132                         elm_image_file_set(img, buf, "NULL");
133                         elm_image_no_scale_set(img, EINA_TRUE);
134                 }
135                 else {
136                         elm_image_file_set(img, path, "NULL");
137                         elm_image_aspect_fixed_set(img, EINA_FALSE);
138                 }
139                 return img;
140         }
141
142         return NULL;
143 }
144
145
146 void CAlbumLayout::sm_CbRemoveGridItem(void *data, Evas_Object *obj)
147 {
148         free(data);
149 }
150
151
152 void CAlbumLayout::sm_CbCtxtUpdate(void *dt, enum EActionType type, int lid)
153 {
154         CAlbumLayout *root = (CAlbumLayout*)dt;
155
156         if (root)
157                 root->m_OnCtxtUpdate(type, lid);
158 }
159
160
161 void CAlbumLayout::m_OnCtxtUpdate(EActionType type, int lid)
162 {
163         Eina_List *list = NULL;
164         CSongInfo *sinfo = NULL;
165         EAddType mode;
166
167         if (!m->ctxtinfo || !m->ctxtinfo->context)
168                 return;
169
170         if (type == ACTION_TYPE_ADDNEXT)
171                 mode = ADD_TYPE_NEXT;
172         else
173                 mode = ADD_TYPE_END;
174
175         m->mhandle->MediaGetList(LIST_TYPE_ALBUM_SONG,
176                 m->ctxtinfo->context, &list);
177         if (type ==  ACTION_TYPE_ADDTO) {
178                 if (!m->mhandle->MediaAddsongsPlaylist(lid, list))
179                         _ERR(" Adding songs to playlist failed ");
180                 else
181                         _create_message_box(m->base, MUSIC_TEXT_ADDTO_MSG);
182
183                 return;
184         }
185
186         m->mhandle->UpdatePlaylist(list, mode);
187         sinfo = (CSongInfo *)eina_list_data_get(list);
188         eina_list_free(list);
189
190         if (type == ACTION_TYPE_PLAY) {
191                 m->mhandle->Stop();
192                 m->mhandle->SetCurrentSong(sinfo->Id());
193         }
194
195         _update_playback_view((EAddType)type, m->parent->Layout(), m->focused_item);
196 }
197
198
199 void CAlbumLayout::sm_CbCtxtClose(void *dt)
200 {
201         CAlbumLayout *root = (CAlbumLayout*)dt;
202
203         if (root)
204                 root->m_OnCtxtClose();
205 }
206
207
208 void CAlbumLayout::m_OnCtxtClose(void)
209 {
210         m->vmgr->PopView();
211         m->vmgr->PushView(MUSIC_BASE_VIEW, NULL);
212         elm_object_item_focus_set(m->focused_item, EINA_TRUE);
213 }
214
215
216 void CAlbumLayout::sm_CbItemSelect(void *data, Elm_Object_Item *it, const char *emission, const char *source) {
217         CAlbumLayout *root = (CAlbumLayout*)data;
218
219         if (root)
220                 root->m_OnItemSelect(it, emission, source);
221 }
222
223
224 void CAlbumLayout::m_OnItemSelect(Elm_Object_Item *it, const char *emission, const char *source) {
225         SAlbumItemInfo *itinfo;
226
227         itinfo = m_FindItemInfo(m->it_infolist, it);
228         if (!itinfo) {
229                 _ERR(" no item info found ");
230                 return;
231         }
232
233         m->mhandle->SetCurrentAlbum(itinfo->alinfo);
234
235         m_ShowAlbumSongs();
236 }
237
238
239 SAlbumItemInfo *CAlbumLayout::m_FindItemInfo(Eina_List *list, Elm_Object_Item *item)
240 {
241         Eina_List *l = NULL;
242         SAlbumItemInfo *itinfo = NULL;
243         void *obj = NULL;
244
245         if (!list || !item)
246                 return NULL;
247
248         EINA_LIST_FOREACH(list, l, obj) {
249                 itinfo = (SAlbumItemInfo *)obj;
250                 if (itinfo->item == item)
251                         return itinfo;
252         }
253
254         return NULL;
255 }
256
257
258 SAlbumItemInfo *CAlbumLayout::m_FindItemInfoById(Eina_List *list, int alid)
259 {
260         Eina_List *l = NULL;
261         SAlbumItemInfo *itinfo = NULL;
262         void *obj = NULL;
263         int id;
264
265         if (!list)
266                 return NULL;
267
268         EINA_LIST_FOREACH(list, l, obj) {
269                 itinfo = (SAlbumItemInfo *)obj;
270                 if (!itinfo->alinfo)
271                         continue;
272                 id = itinfo->alinfo->AlbumId();
273                 if (alid == id) {
274                         return itinfo;
275                 }
276         }
277
278         return NULL;
279 }
280
281
282 void CAlbumLayout::m_ShowAlbumSongs(void)
283 {
284         elm_object_part_content_unset(m->base, MUSIC_PART_CONTENT);
285
286         bool emptyStatus = m->layoutAlbumSongs->EmptyStatus();
287
288         if (emptyStatus == false) {
289                 elm_object_part_content_set(m->base, MUSIC_PART_CONTENT, m->layoutAlbumSongs->Layout());
290                 m->lmgr->Show(MUSIC_ALBUM_SONGS_LAYOUT);
291         }
292
293         if (m->callback.cbHandleEmptyStatus != NULL) {
294                 m->callback.cbHandleEmptyStatus(m->callback.cookie, emptyStatus);
295         }
296 }
297
298
299 void CAlbumLayout::m_RemoveAlbumList(Eina_List *list)
300 {
301         eina_list_free(list);
302 }
303
304
305 void CAlbumLayout::m_CreateAlbumGrid(void)
306 {
307         Evas_Object *grid;
308         Elm_Gengrid_Item_Class *grid_item;
309
310         grid = elm_gengrid_add(Layout());
311         if (!grid)
312                 return;
313
314         evas_object_size_hint_weight_set(grid,
315                 EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
316         elm_gengrid_align_set(grid, 0, 0);
317         elm_object_part_content_set(Layout(), MUSIC_PART_ALBUM_GRID, grid);
318         Connect(grid, ALBUM_GENGRID, TYPE_MOUSE_MOVE | TYPE_KEY_DOWN | TYPE_REALIZED | TYPE_UNREALIZED);
319         elm_gengrid_item_size_set(grid,
320                 elm_config_scale_get() * GENGRID_ITEM_SIZE_W,
321                 elm_config_scale_get() * GENGRID_ITEM_SIZE_H);
322
323         m->grid = grid;
324
325         grid_item = elm_gengrid_item_class_new();
326         if (!grid_item) {
327                 evas_object_del(grid);
328                 _ERR(" elm_genlist_item_class_new failed ");
329                 return;
330         }
331
332         grid_item->item_style = MUSIC_STYLE_ALBUM_GRID;
333         grid_item->func.text_get = sm_CbGetGridItemText;
334         grid_item->func.content_get = sm_CbGetGridItemContent;
335         grid_item->func.state_get = NULL;
336         grid_item->func.del = sm_CbRemoveGridItem;
337         m->item_class = grid_item;
338
339         m_UpdateAlbumGrid(false);
340 }
341
342
343 void CAlbumLayout::m_EmptyAlbumGrid(bool sort_flag)
344 {
345         if (m->grid)
346                 elm_gengrid_clear(m->grid);
347
348         if (!sort_flag) {
349                 m_RemoveAlbumList(m->alblist);
350                 m->alblist = NULL;
351         }
352
353         eina_list_free(m->it_infolist);
354         m->it_infolist = NULL;
355 }
356
357
358 void CAlbumLayout::m_SortAlbumGrid(void)
359 {
360         int sortType;
361         const char *sortFuncId[] = {
362                 SORT_BY_NAME_AZ,
363                 SORT_BY_NAME_ZA,
364         };
365
366         sortType = m->mhandle->SortType();
367
368         m->alblist = CSort::Sort(m->alblist, sortFuncId[sortType]);
369 }
370
371
372 void CAlbumLayout::m_UpdateAlbumGrid(bool sort_flag)
373 {
374         bool r;
375         CAlbumInfo *alinfo;
376         void *obj;
377         Eina_List *l;
378         SAlbumItemInfo *itinfo;
379         Elm_Object_Item *item;
380
381         /* Remove existing albumgrid and prepare afresh */
382         m_EmptyAlbumGrid(sort_flag);
383
384         if (!sort_flag) {
385                 r = m->mhandle->MediaGetList(LIST_TYPE_ALBUM, NULL, &(m->alblist));
386                 if (r == false ||
387                         eina_list_count(m->alblist) == 0) {
388                         _ERR(" Fetching album list from media failed ");
389                         m->parent->SetEmptyStatus(true);
390                         return;
391                 }
392         }
393
394         m_SortAlbumGrid();
395
396         EINA_LIST_FOREACH(m->alblist, l, obj) {
397                 alinfo = (CAlbumInfo *)obj;
398                 itinfo = (SAlbumItemInfo *)calloc(1, sizeof(*itinfo));
399                 if (!itinfo)
400                         return;
401
402                 itinfo->alinfo = alinfo;
403                 item = elm_gengrid_item_append(m->grid, m->item_class, itinfo, NULL, NULL);
404                 itinfo->item = item;
405                 m->it_infolist = eina_list_append(m->it_infolist, itinfo);
406         }
407 }
408
409
410 bool CAlbumLayout::Create(CLayoutMgr *mgr, const char *albumId)
411 {
412         ASSERT(!m);
413
414         Evas_Object *base = NULL;
415         Evas_Object *win = NULL;
416         Evas_Object *layout = NULL;
417         CMusicController *mhandle = NULL;
418         CViewMgr *vmgr = NULL;
419
420         m = new SAlbumLayout;
421         if (!m) {
422                 _ERR(" albumlayout data allocation failed ");
423                 return false;
424         }
425
426         vmgr = CViewMgr::GetInstance();
427         if (!vmgr) {
428                 _ERR(" get viewmgr failed ");
429                 delete m;
430                 m = NULL;
431                 return false;
432         }
433
434         base = mgr->Base();
435         if (!base) {
436                 _ERR(" get base failed ");
437                 delete m;
438                 m = NULL;
439                 return false;
440         }
441
442         win = vmgr->Window();
443         if (!win) {
444                 _ERR(" vimewmgr get win failed ");
445                 delete m;
446                 m = NULL;
447                 return false;
448         }
449
450         mhandle = CMusicController::GetInstance();
451         if (!mhandle) {
452                 _ERR(" music controller get music instance failed ");
453                 delete m;
454                 m = NULL;
455                 return false;
456         }
457
458         layout = _add_base(base, MUSIC_ALBUM_LAYOUT);
459         if (!layout) {
460                 _ERR(" get layout failed ");
461                 delete m;
462                 m = NULL;
463                 return false;
464         }
465
466         bool r = CExtBaseLayout::Create(layout);
467         if (!r) {
468                 _ERR(" CBaseLayout creation failed ");
469                 evas_object_del(layout);
470                 delete m;
471                 m = NULL;
472                 return false;
473         }
474
475         if (albumId) {
476                 m->album_id = new char[strlen(albumId) + 1];
477                 strcpy(m->album_id, albumId);
478         }
479         else {
480                 m->album_id = NULL;
481         }
482
483         m->win = win;
484         m->base = base;
485         m->vmgr = vmgr;
486         m->mhandle = mhandle;
487         m->lmgr = mgr;
488         m->callback.cbHandleEmptyStatus = NULL;
489         m->callback.cookie = NULL;
490         m->parent = this;
491
492         m->layoutAlbumSongs = new CAlbumSongsLayout(MUSIC_ALBUM_SONGS_LAYOUT);
493         m->layoutAlbumSongs->Create(m->lmgr);
494         m->lmgr->AddLayout(m->layoutAlbumSongs);
495
496         m_CreateAlbumGrid();
497
498         Connect(layout, ALBUM_LAYOUT, TYPE_KEY_DOWN);
499
500         SParcel parcel;
501         parcel.ctxtInfo = NULL;
502         parcel.updateType = E_LAYOUT_UPDATE;
503         parcel.layoutId = MUSIC_ALBUM_LAYOUT;
504         parcel.keyEvent = NULL;
505         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
506
507         return true;
508 }
509
510 void CAlbumLayout::Destroy(void)
511 {
512         ASSERT(m);
513
514         m->lmgr->RemoveLayout(m->layoutAlbumSongs);
515         m->layoutAlbumSongs->Destroy();
516         delete m->layoutAlbumSongs;
517
518         m_EmptyAlbumGrid(false);
519         CExtBaseLayout::Destroy();
520         evas_object_del(Layout());
521
522         free(m->ctxtinfo);
523         delete[] m->album_id;
524         delete m;
525         m = NULL;
526 }
527
528
529 void CAlbumLayout::t_OnShow(void)
530 {
531         ASSERT(m);
532
533         SAlbumItemInfo *itinfo = NULL;
534
535         m_UpdateAlbumGrid(false);
536
537         SParcel parcel;
538         parcel.ctxtInfo = NULL;
539         parcel.updateType = E_LAYOUT_UPDATE;
540         parcel.layoutId = MUSIC_ALBUM_LAYOUT;
541         parcel.keyEvent = NULL;
542         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
543
544         evas_object_show(Layout());
545
546         if (m->album_id) {
547                 itinfo = m_FindItemInfoById(m->it_infolist,
548                         atoi(m->album_id));
549                 if (itinfo) {
550                         m->mhandle->SetCurrentAlbum(itinfo->alinfo);
551                         m_ShowAlbumSongs();
552                         return;
553                 }
554                 delete[] m->album_id;
555                 m->album_id = NULL;
556         }
557 }
558
559
560 void CAlbumLayout::Update(bool focusFlag)
561 {
562         ASSERT(m);
563
564         CAlbumInfo *alinfo = NULL;
565         SAlbumItemInfo *itinfo = NULL;
566         int id;
567
568         if (!focusFlag) {
569                 m_UpdateAlbumGrid(true);
570                 return;
571         }
572
573         alinfo = m->mhandle->CurrentAlbum();
574         if (alinfo) {
575                 id = alinfo->AlbumId();
576                 itinfo = m_FindItemInfoById(m->it_infolist, id);
577                 if (itinfo) {
578                         m->mhandle->SetCurrentAlbum(NULL);
579                         elm_gengrid_item_show(itinfo->item,
580                                 ELM_GENGRID_ITEM_SCROLLTO_IN);
581                         elm_object_item_focus_set(itinfo->item, EINA_TRUE);
582                         return;
583                 }
584         }
585
586         elm_object_focus_set(m->grid, EINA_TRUE);
587 }
588
589
590 void CAlbumLayout::SetEmptyStatusHandleCallback(void(*handleEmptyStatusCb)(void *cookie, bool emptyStatus), void *cookie)
591 {
592         ASSERT(m);
593
594         m->callback.cbHandleEmptyStatus = handleEmptyStatusCb;
595         m->callback.cookie = cookie;
596 }
597
598
599 void CAlbumLayout::OnKeyDown(int id, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev)
600 {
601         switch (id) {
602         case ALBUM_LAYOUT:
603                 if (!strcmp(ev->keyname, KEY_BACK)) {
604                         SParcel parcel;
605                         parcel.ctxtInfo = NULL;
606                         parcel.updateType = E_FOCUS_UPDATE;
607                         parcel.layoutId = NULL;
608                         parcel.keyEvent = NULL;
609                         m->vmgr->UpdateView((const char *)MUSIC_BASE_VIEW, &parcel);
610                 }
611                 break;
612
613         case ALBUM_GENGRID:
614                 {
615                         Elm_Object_Item *it = NULL;
616                         SContentInfo *ctxtinfo = NULL;
617                         SAlbumItemInfo *itinfo = NULL;
618
619                         if (strcmp(ev->keyname, KEY_MENU))
620                                 return;
621
622                         it = elm_object_focused_item_get(obj);
623                         if (!it) {
624                                 _ERR(" unable to get focused item ");
625                                 return;
626                         }
627                         m->focused_item = it;
628
629                         if (m->ctxtinfo) {
630                                 free(m->ctxtinfo);
631                                 m->ctxtinfo = NULL;
632                         }
633
634                         ctxtinfo = (SContentInfo *)calloc(1, sizeof(*ctxtinfo));
635                         if (!ctxtinfo)
636                                 return;
637
638                         itinfo = m_FindItemInfo(m->it_infolist, it);
639                         if (!itinfo) {
640                                 free(ctxtinfo);
641                                 return;
642                         }
643
644                         ctxtinfo->type = CONTEXT_TYPE_ALBUM;
645                         ctxtinfo->context = itinfo->alinfo;
646                         ctxtinfo->cbdata = this;
647                         ctxtinfo->update = sm_CbCtxtUpdate;
648                         ctxtinfo->close = sm_CbCtxtClose;
649
650                         m->ctxtinfo = ctxtinfo;
651
652                         SParcel parcel;
653                         parcel.ctxtInfo = ctxtinfo;
654                         if (!m->vmgr->PushView(MUSIC_CONTEXT_VIEW, &parcel))
655                                 _ERR("viewmgr push view MUSIC_CONTEXT_VIEW failed");
656                 }
657                 break;
658
659         default:
660                 _ERR("Invalid Object");
661                 ASSERT(0);
662                 break;
663         }
664 }
665
666
667 void CAlbumLayout::OnMouseMove(int id, Evas *e, Evas_Object *obj, Evas_Event_Mouse_Move *ev)
668 {
669         Elm_Object_Item *item;
670
671         item = elm_gengrid_at_xy_item_get(obj, ev->cur.canvas.x,
672                 ev->cur.canvas.y, NULL, NULL);
673         if (!item)
674                 return;
675
676         if (!elm_object_item_focus_get(item))
677                 elm_object_item_focus_set(item, EINA_TRUE);
678 }
679
680
681 void CAlbumLayout::OnRealized(int id, Evas_Object *obj, Elm_Object_Item *item)
682 {
683         elm_object_item_signal_callback_add(item,
684                 MUSIC_SIGNAL_BTN_CLICKED, MUSIC_BASE_VIEW,
685                 sm_CbItemSelect, this);
686 }
687
688
689 void CAlbumLayout::OnUnrealized(int id, Evas_Object *obj, Elm_Object_Item *item)
690 {
691         elm_object_item_signal_callback_del(item,
692                 MUSIC_SIGNAL_BTN_CLICKED, MUSIC_BASE_VIEW,
693                 sm_CbItemSelect);
694 }