/* * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "define.h" #include "layout.h" #include "view.h" #include "util/ctxpopup.h" #include "util/util.h" #define TITLE_TEXT "Media Hub" #define TEXT_FAVORITE_ADDED "Added to your favorite." #define TEXT_FAVORITE_REMOVED "Removed from your favorite." #define BOX_PADDING_SIZE 80 #define TIME_TOAST_FAVORITE 5.0 #define ARRAY_SIZE(arr) (sizeof(arr)) / (sizeof((arr)[0])) enum _object_type { BASE_MENU_BTN = 0, BASE_VIEW_BTN }; enum _layout_type { E_LAYOUT_MOVIE = 0, E_LAYOUT_GALLERY, E_LAYOUT_MUSIC, E_LAYOUT_MAX }; struct _priv { Evas_Object *win; Evas_Object *base; Evas_Object *menu_btn[E_LAYOUT_MAX]; Evas_Object *view_btn; Evas_Object *focused_btn; Evas_Object *notify; struct ctxpopup *cpopup; layoutmgr *lmgr; Eina_List *favorite_list; app_media *recent_item; int current_layout; int view_mode[E_LAYOUT_MAX]; }; const char *view_mode_movie[] = { "Name", "Genre", "Date", "Folder" }; const char *view_mode_gallery[] = { "Event", "Place", "Video", "Folder" }; const char *view_mode_music[] = { "Song", "Album", "Artist", "Genre", "Folder" }; struct _menu_item { const char *name; const char *layout_id; layout_class *(*func_get_lclass)(void); const char **text_view_mode; int text_size; }; static struct _menu_item g_menu_item[E_LAYOUT_MAX] = { [E_LAYOUT_MOVIE] = { "Movie", LAYOUT_MOVIE, layout_movie_get_lclass, view_mode_movie, ARRAY_SIZE(view_mode_movie) }, [E_LAYOUT_GALLERY] = { "Gallery", LAYOUT_GALLERY, layout_gallery_get_lclass, view_mode_gallery, ARRAY_SIZE(view_mode_gallery) }, [E_LAYOUT_MUSIC] = { "Music", LAYOUT_MUSIC, layout_music_get_lclass, view_mode_music, ARRAY_SIZE(view_mode_music) } }; static void _set_current_layout(struct _priv *priv, int layout) { int mode; layoutmgr_hide_layout(priv->lmgr, g_menu_item[priv->current_layout].layout_id); layoutmgr_show_layout(priv->lmgr, g_menu_item[layout].layout_id); mode = priv->view_mode[layout]; elm_object_text_set(priv->view_btn, g_menu_item[layout].text_view_mode[mode]); if (priv->focused_btn) elm_object_signal_emit(priv->focused_btn, SIG_BTN_UNSELECTED, SIG_SOURCE_SRC); priv->focused_btn = priv->menu_btn[layout]; priv->current_layout = layout; } static void _update_layout(struct _priv *priv, Evas_Object *obj) { int i; for (i = 0; i < E_LAYOUT_MAX; i++) { if (priv->menu_btn[i] == obj) break; } if (i == E_LAYOUT_MAX) return; layoutmgr_update_layout(priv->lmgr, g_menu_item[i].layout_id, UPDATE_FOCUS_STATE, NULL); if (priv->focused_btn == obj) return; _set_current_layout(priv, i); layoutmgr_update_layout(priv->lmgr, g_menu_item[i].layout_id, UPDATE_CONTENT, NULL); } static void _view_selected_cb(void *data, int mode) { struct view_update_data vdata; struct _priv *priv; int cur; if (!data) return; priv = data; cur = priv->current_layout; elm_object_text_set(priv->view_btn, g_menu_item[cur].text_view_mode[mode]); vdata.index = mode; layoutmgr_update_layout(priv->lmgr, g_menu_item[cur].layout_id, UPDATE_VIEW_MODE, &vdata); priv->view_mode[cur] = mode; } static void _key_down_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Key_Down *ev) { if (!obj || !ev) return; switch (id) { case BASE_MENU_BTN: if (!strcmp(ev->keyname, KEY_ENTER)) elm_object_focus_next(obj, ELM_FOCUS_DOWN); else if (!strcmp(ev->keyname, KEY_BACK) || !strcmp(ev->keyname, KEY_ESC)) ui_app_exit(); break; default: break; } } static void _mouse_move_cb(int id, void *data, Evas *e, Evas_Object *obj, Evas_Event_Mouse_Move *ev) { if (!obj) return; if (!elm_object_focus_get(obj)) elm_object_focus_set(obj, EINA_TRUE); } static void _focused_cb(int id, void *data, Evas_Object *obj, Elm_Object_Item *it) { struct _priv *priv; if (!data) { _ERR("failed to get data"); return; } priv = data; switch (id) { case BASE_MENU_BTN: _update_layout(priv, obj); break; default: break; } } static void _view_btn_clicked(struct _priv *priv) { struct ctxpopup *cpopup; int x, y, w, h; cpopup = ctxpopup_create(priv->base, STYLE_CTXPOPUP_VIEW_MODE, STYLE_BTN_VIEW_OPTION, g_menu_item[priv->current_layout].text_view_mode, g_menu_item[priv->current_layout].text_size, priv->view_mode[priv->current_layout]); if (!cpopup) { _ERR("failed to create ctxpopup"); return; } ctxpopup_set_callback(cpopup, _view_selected_cb, priv); evas_object_geometry_get(priv->view_btn, &x, &y, &w, &h); ctxpopup_show(cpopup, x + (w / 2), y); priv->cpopup = cpopup; } static void _clicked_cb(int id, void *data, Evas_Object *obj) { struct _priv *priv; if (!data) { _ERR("failed to get data"); return; } priv = data; switch (id) { case BASE_VIEW_BTN: _view_btn_clicked(priv); break; default: break; } } static input_handler handler = { .key_down = _key_down_cb, .mouse_move = _mouse_move_cb, .clicked = _clicked_cb, .focused = _focused_cb }; static app_media *_get_app_media(const char *id) { media_info_h media; app_media *am; int r; r = media_info_get_media_from_db(id, &media); if (r != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get media handle"); return NULL; } am = app_media_create(media); if (!am) { _ERR("failed to create app media"); return NULL; } return am; } static int _get_content_type(app_media_info *info) { int type; type = -1; switch (info->media_type) { case MEDIA_CONTENT_TYPE_IMAGE: type = CONTENTS_GALLERY; break; case MEDIA_CONTENT_TYPE_VIDEO: if (util_check_movie_type(info->video->copyright)) type = CONTENTS_MOVIE; else type = CONTENTS_GALLERY; break; case MEDIA_CONTENT_TYPE_MUSIC: type = CONTENTS_MUSIC; break; default: break; } return type; } static void _favorite_list_foreach(gpointer data, gpointer user_data) { media_info_h media; app_media *am; Eina_List **l; int r; char *id; if (!data || !user_data) { _ERR("invalid argument"); return; } id = (char *)data; l = (Eina_List **)user_data; r = media_info_get_media_from_db(id, &media); if (r != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to get media handle"); return; } am = app_media_create(media); if (!am) { _ERR("failed to create app media"); media_info_destroy(media); return; } *l = eina_list_append(*l, am); } static void _free_favorite_list(Eina_List *list) { app_media *am; EINA_LIST_FREE(list, am) app_media_destroy(am); } static Eina_List *_get_favorite_list(int type) { GList *id_list; Eina_List *list; id_list = NULL; if (app_contents_get_favorite_list(type, &id_list) != APP_CONTENTS_ERROR_NONE) { _ERR("failed to get favorite list"); return NULL; } list = NULL; g_list_foreach(id_list, _favorite_list_foreach, &list); app_contents_free_favorite_list(id_list); return list; } static int _get_media_index(Eina_List *list, const char *id) { Eina_List *l; app_media *am; app_media_info *info; int index; index = 0; EINA_LIST_FOREACH(list, l, am) { info = app_media_get_info(am); if (!info) continue; if (!strcmp(id, info->media_id)) return index; index++; } return -1; } static void _update_favorite_view(struct _priv *priv, const char *id) { app_media *am; app_media_info *info; struct view_update_data vdata; int type; int r; r = media_content_connect(); if (r != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to connect to media content"); return; } am = _get_app_media(id); if (!am) { _ERR("failed to get app media"); return; } info = app_media_get_info(am); if (!info) { _ERR("failed to get app media info"); app_media_destroy(am); return; } type = _get_content_type(info); vdata.list = _get_favorite_list(type); vdata.index = _get_media_index(vdata.list, info->media_id); vdata.id = NULL; if (type == CONTENTS_MOVIE || type == CONTENTS_GALLERY) { viewmgr_update_view(VIEW_VIEWER, UPDATE_CONTENT, &vdata); viewmgr_push_view(VIEW_VIEWER); } else if (type == CONTENTS_MUSIC) { viewmgr_update_view(VIEW_MPLAYER, UPDATE_CONTENT, &vdata); viewmgr_push_view(VIEW_MPLAYER); } priv->favorite_list = vdata.list; app_media_destroy(am); media_content_disconnect(); } static int _get_layout_type(app_media_info *info) { int type; type = E_LAYOUT_MAX; switch (info->media_type) { case MEDIA_CONTENT_TYPE_IMAGE: type = E_LAYOUT_GALLERY; break; case MEDIA_CONTENT_TYPE_VIDEO: if (util_check_movie_type(info->video->copyright)) type = E_LAYOUT_MOVIE; else type = E_LAYOUT_GALLERY; break; case MEDIA_CONTENT_TYPE_MUSIC: type = E_LAYOUT_MUSIC; break; default: break; } return type; } static void _update_recent_view(struct _priv *priv, const char *id) { app_media *am; app_media_info *info; int type; int r; r = media_content_connect(); if (r != MEDIA_CONTENT_ERROR_NONE) { _ERR("failed to connect to media content"); return; } am = _get_app_media(id); if (!am) { _ERR("failed to get app media"); return; } info = app_media_get_info(am); if (!info) { _ERR("failed to get app media info"); app_media_destroy(am); return; } type = _get_layout_type(info); _set_current_layout(priv, type); layoutmgr_update_layout(priv->lmgr, g_menu_item[type].layout_id, UPDATE_RECENT, am); priv->recent_item = am; media_content_disconnect(); } static bool _draw_title(struct _priv *priv) { if (!priv) return false; elm_object_part_text_set(priv->base, PART_BASE_TITLE, TITLE_TEXT); return true; } static bool _draw_menu_btn(struct _priv *priv) { Evas_Object *box, *btn; int i; if (!priv) return false; box = elm_box_add(priv->base); if (!box) { _ERR("failed to create box object"); return false; } elm_box_horizontal_set(box, EINA_TRUE); elm_box_padding_set(box, BOX_PADDING_SIZE, 0); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); for (i = 0; i < E_LAYOUT_MAX; i++) { btn = util_add_button(box, STYLE_BTN_MENU, g_menu_item[i].name); if (!btn) { _ERR("failed to add button object"); evas_object_del(box); return false; } elm_box_pack_end(box, btn); evas_object_show(btn); inputmgr_add_callback(btn, BASE_MENU_BTN, &handler, priv); priv->menu_btn[i] = btn; } evas_object_show(box); elm_object_part_content_set(priv->base, PART_BASE_MENU_AREA, box); elm_object_focus_next_object_set(priv->menu_btn[E_LAYOUT_MAX - 1], priv->menu_btn[0], ELM_FOCUS_RIGHT); elm_object_focus_next_object_set(priv->menu_btn[0], priv->menu_btn[E_LAYOUT_MAX - 1], ELM_FOCUS_LEFT); return true; } static bool _draw_view_mode_btn(struct _priv *priv) { Evas_Object *btn; btn = util_add_button(priv->base, STYLE_BTN_VIEW_MODE, NULL); if (!btn) { _ERR("failed to add button object"); return false; } inputmgr_add_callback(btn, BASE_VIEW_BTN, &handler, priv); elm_object_part_content_set(priv->base, PART_BASE_VIEW_MODE, btn); elm_object_focus_next_object_set(btn, btn, ELM_FOCUS_RIGHT); priv->view_btn = btn; return true; } static bool _draw_items(struct _priv *priv) { if (!priv) return false; if (!_draw_title(priv)) return false; if (!_draw_menu_btn(priv)) return false; if (!_draw_view_mode_btn(priv)) return false; return true; } static void _hide_toast_favorite(struct _priv *priv) { if (priv->notify) evas_object_hide(priv->notify); } static void _show_toast_favorite(struct _priv *priv, const char *id) { Evas_Object *notify; int r; bool favorite; r = app_contents_favorite_check(CONTENTS_MEDIA, id, &favorite); if (r != APP_CONTENTS_ERROR_NONE) { _ERR("failed to check favorite"); return; } if (favorite) notify = util_add_notify(priv->base, STYLE_TOAST, STYLE_TOAST, TEXT_FAVORITE_ADDED, TIME_TOAST_FAVORITE); else notify = util_add_notify(priv->base, STYLE_TOAST, STYLE_TOAST, TEXT_FAVORITE_REMOVED, TIME_TOAST_FAVORITE); if (!notify) { _ERR("failed to add notify object"); return; } priv->notify = notify; } static Evas_Object *_create(Evas_Object *win, void *data) { struct layout_data ldata; struct _priv *priv; Evas_Object *base; layoutmgr *lmgr; int i; if (!win) { _ERR("failed to get win object"); return NULL; } priv = calloc(1, sizeof(*priv)); if (!priv) { _ERR("failed to allocate priv"); return NULL; } base = elm_layout_add(win); if (!base) { _ERR("failed to create base object"); free(priv); return NULL; } elm_layout_file_set(base, EDJEFILE, GRP_BASE_VIEW); evas_object_size_hint_weight_set(base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(win, base); priv->win = win; priv->base = base; if (!_draw_items(priv)) { _ERR("failed to draw items"); free(priv); return NULL; } lmgr = layoutmgr_create(base); for (i = 0; i < E_LAYOUT_MAX; i++) { ldata.top = priv->menu_btn[i]; ldata.bottom = priv->view_btn; layoutmgr_add_layout(lmgr, g_menu_item[i].func_get_lclass(), &ldata); } priv->lmgr = lmgr; viewmgr_set_view_data(VIEW_BASE, priv); elm_object_focus_set(priv->menu_btn[0], EINA_TRUE); return base; } static Eina_Bool _show_view(void *data) { struct _priv *priv; if (!data) return ECORE_CALLBACK_CANCEL; priv = data; elm_object_signal_emit(priv->base, SIG_SHOW_VIEW, ""); return ECORE_CALLBACK_CANCEL; } static void _show(void *view_data) { struct _priv *priv; if (!view_data) { _ERR("failed to get view data"); return; } priv = view_data; evas_object_show(priv->base); ecore_timer_add(SHOW_VIEW_INTERVAL, _show_view, priv); } static void _hide(void *view_data) { struct _priv *priv; if (!view_data) { _ERR("failed to get view data"); return; } priv = view_data; evas_object_hide(priv->base); elm_object_signal_emit(priv->base, SIG_HIDE_VIEW, ""); } static void _update(void *view_data, int update_type, void *data) { struct _priv *priv; struct view_update_data *vdata; if (!view_data) { _ERR("failed to get view data"); return; } priv = view_data; switch (update_type) { case UPDATE_FOCUS: case UPDATE_PLAY_INFO: if (!data) goto err; vdata = data; layoutmgr_update_layout(priv->lmgr, g_menu_item[priv->current_layout].layout_id, update_type, vdata); break; case UPDATE_CONTENT_ITEM: case UPDATE_BACK: layoutmgr_update_layout(priv->lmgr, g_menu_item[priv->current_layout].layout_id, update_type, NULL); break; case UPDATE_TOAST: if (!data) goto err; vdata = data; if (vdata->status == E_TOAST_SHOW) _show_toast_favorite(priv, vdata->id); else _hide_toast_favorite(priv); break; case UPDATE_FAVORITE: if (!data) goto err; _update_favorite_view(priv, data); break; case UPDATE_RECENT: if (!data) goto err; _update_recent_view(priv, data); break; default: break; } return; err: _ERR("invalid argument"); } static void _pause(void *view_data) { struct view_update_data vdata; vdata.status = E_PLAYER_STOP; viewmgr_update_view(VIEW_MPLAYER, UPDATE_PLAYER, &vdata); } static void _destroy(void *view_data) { struct _priv *priv; int i; if (!view_data) { _ERR("failed to get view data"); return; } priv = view_data; for (i = 0; i < E_LAYOUT_MAX; i++) inputmgr_remove_callback(priv->menu_btn[i], &handler); layoutmgr_remove_layout(priv->lmgr, LAYOUT_MOVIE); layoutmgr_remove_layout(priv->lmgr, LAYOUT_GALLERY); layoutmgr_remove_layout(priv->lmgr, LAYOUT_MUSIC); layoutmgr_destroy(priv->lmgr); if (priv->favorite_list) _free_favorite_list(priv->favorite_list); app_media_destroy(priv->recent_item); evas_object_del(priv->base); free(priv); } static view_class _vclass = { .view_id = VIEW_BASE, .create = _create, .show = _show, .hide = _hide, .update = _update, .pause = _pause, .destroy = _destroy, }; view_class *view_base_get_vclass(void) { return &_vclass; }