package tv.emby.embyatv.util;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.widget.PopupMenu;
import java.util.List;
import mediabrowser.apiinteraction.EmptyResponse;
import mediabrowser.apiinteraction.Response;
import mediabrowser.model.dto.BaseItemDto;
import mediabrowser.model.dto.UserItemDataDto;
import mediabrowser.model.entities.SortOrder;
import mediabrowser.model.querying.ItemFilter;
import mediabrowser.model.querying.ItemsResult;
import tv.emby.embyatv.R;
import tv.emby.embyatv.TvApp;
import tv.emby.embyatv.base.BaseActivity;
import tv.emby.embyatv.base.CustomMessage;
import tv.emby.embyatv.details.PhotoPlayerActivity;
import tv.emby.embyatv.details.ItemListActivity;
import tv.emby.embyatv.itemhandling.AudioQueueItem;
import tv.emby.embyatv.itemhandling.BaseRowItem;
import tv.emby.embyatv.playback.AudioNowPlayingActivity;
import tv.emby.embyatv.playback.MediaManager;
import tv.emby.embyatv.playback.PlaybackOverlayActivity;
import tv.emby.embyatv.querying.StdItemQuery;
/**
* Created by Eric on 4/17/2015.
*/
public class KeyProcessor {
public static final int MENU_MARK_FAVORITE = 0;
public static final int MENU_UNMARK_FAVORITE = 1;
public static final int MENU_LIKE = 2;
public static final int MENU_DISLIKE = 3;
public static final int MENU_UNLIKE = 4;
public static final int MENU_UNDISLIKE = 5;
public static final int MENU_MARK_PLAYED = 6;
public static final int MENU_UNMARK_PLAYED = 7;
public static final int MENU_PLAY = 8;
public static final int MENU_PLAY_SHUFFLE = 9;
public static final int MENU_PLAY_FIRST_UNWATCHED = 10;
public static final int MENU_ADD_QUEUE = 11;
public static final int MENU_ADVANCE_QUEUE = 12;
public static final int MENU_REMOVE_FROM_QUEUE = 13;
public static final int MENU_GOTO_NOW_PLAYING = 14;
public static final int MENU_INSTANT_MIX = 15;
public static final int MENU_FORGET = 16;
private static String mCurrentItemId;
private static BaseItemDto mCurrentItem;
private static BaseActivity mCurrentActivity;
private static int mCurrentRowItemNdx;
private static boolean currentItemIsFolder = false;
private static boolean isMusic;
public static boolean HandleKey(int key, BaseRowItem rowItem, BaseActivity activity) {
if (rowItem == null) return false;
switch (key) {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (MediaManager.isPlayingAudio() && (!rowItem.isBaseItem() || !rowItem.getBaseItem().getType().equals("Photo"))) {
MediaManager.pauseAudio();
return true;
}
switch (rowItem.getItemType()) {
case BaseItem:
BaseItemDto item = rowItem.getBaseItem();
if (!Utils.CanPlay(item)) return false;
switch (item.getType()) {
case "Audio":
if (rowItem instanceof AudioQueueItem) {
createItemMenu(rowItem, item.getUserData(), activity);
return true;
}
//fall through...
case "Movie":
case "Episode":
case "TvChannel":
case "Video":
case "Program":
case "ChannelVideoItem":
case "Trailer":
// give some audible feedback
Utils.Beep();
// retrieve full item and play
Utils.retrieveAndPlay(item.getId(), false, activity);
return true;
case "Series":
case "Season":
case "BoxSet":
createPlayMenu(rowItem.getBaseItem(), true, false, activity);
return true;
case "MusicAlbum":
case "MusicArtist":
createPlayMenu(rowItem.getBaseItem(), true, true, activity);
return true;
case "Playlist":
createPlayMenu(rowItem.getBaseItem(), true, "Audio".equals(rowItem.getBaseItem().getMediaType()), activity);
return true;
case "Photo":
// open photo player
Utils.Beep();
Intent photoIntent = new Intent(activity, PhotoPlayerActivity.class);
photoIntent.putExtra("Play",true);
activity.startActivity(photoIntent);
return true;
}
break;
case Person:
break;
case Server:
break;
case User:
break;
case Chapter:
break;
case SearchHint:
switch (rowItem.getSearchHint().getType()) {
case "Movie":
case "Episode":
case "TvChannel":
case "Video":
case "Program":
// give some audible feedback
Utils.Beep();
// retrieve full item and play
Utils.retrieveAndPlay(rowItem.getItemId(), false, activity);
return true;
case "Series":
case "Season":
case "BoxSet":
createPlayMenu(rowItem.getBaseItem(), true, false, activity);
return true;
}
break;
case LiveTvChannel:
case LiveTvRecording:
// give some audible feedback
Utils.Beep();
// retrieve full item and play
Utils.retrieveAndPlay(rowItem.getItemId(), false, activity);
return true;
case LiveTvProgram:
// give some audible feedback
Utils.Beep();
// retrieve channel this program belongs to and play
Utils.retrieveAndPlay(rowItem.getProgramInfo().getChannelId(), false, activity);
return true;
case GridButton:
if (rowItem.getGridButton().getId() == TvApp.VIDEO_QUEUE_OPTION_ID) {
//Queue already there - just kick off playback
Utils.Beep();
Intent intent = new Intent(activity, PlaybackOverlayActivity.class);
activity.startActivity(intent);
}
break;
}
if (MediaManager.hasAudioQueueItems()) {
MediaManager.resumeAudio();
return true;
}
break;
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_BUTTON_Y:
TvApp.getApplication().getLogger().Debug("Menu for: "+rowItem.getFullName());
//Create a contextual menu based on item
switch (rowItem.getItemType()) {
case BaseItem:
BaseItemDto item = rowItem.getBaseItem();
switch (item.getType()) {
case "Movie":
case "Episode":
case "TvChannel":
case "Video":
case "Program":
case "ChannelVideoItem":
case "Series":
case "Season":
case "BoxSet":
case "MusicAlbum":
case "MusicArtist":
case "Playlist":
case "Audio":
case "Trailer":
// generate a standard item menu
createItemMenu(rowItem, item.getUserData(), activity);
break;
}
break;
case Person:
break;
case Server:
createServerMenu(rowItem, activity);
break;
case User:
break;
case Chapter:
break;
case SearchHint:
break;
case LiveTvChannel:
break;
case LiveTvRecording:
break;
case GridButton:
break;
case LiveTvProgram:
break;
}
return true;
}
return false;
}
private static void createServerMenu(final BaseRowItem rowItem, final BaseActivity activity) {
PopupMenu menu = Utils.createPopupMenu(activity, activity.getCurrentFocus(), Gravity.TOP);
menu.getMenu().add(0, MENU_FORGET, 0, R.string.lbl_forget);
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_FORGET:
TvApp.getApplication().getConnectionManager().DeleteServer(rowItem.getItemId(), new EmptyResponse() {
@Override
public void onResponse() {
activity.sendMessage(CustomMessage.RemoveCurrentItem);
}
});
return true;
default:
return false;
}
}
});
menu.show();
}
private static void createItemMenu(BaseRowItem rowItem, UserItemDataDto userData, BaseActivity activity) {
BaseItemDto item = rowItem.getBaseItem();
PopupMenu menu = Utils.createPopupMenu(activity, activity.getCurrentFocus(), Gravity.RIGHT);
int order = 0;
if (rowItem instanceof AudioQueueItem) {
if (!(activity instanceof AudioNowPlayingActivity)) menu.getMenu().add(0, MENU_GOTO_NOW_PLAYING, order++, R.string.lbl_goto_now_playing);
if (rowItem.getBaseItem() != MediaManager.getCurrentAudioItem()) menu.getMenu().add(0, MENU_ADVANCE_QUEUE, order++, R.string.lbl_play_from_here);
// don't allow removal of last item - framework will crash trying to animate an empty row
if (MediaManager.getCurrentAudioQueue().size() > 1) menu.getMenu().add(0, MENU_REMOVE_FROM_QUEUE, order++, R.string.lbl_remove_from_queue);
} else {
if (Utils.CanPlay(item)) {
if (item.getIsFolder() && !"MusicAlbum".equals(item.getType()) && !"Playlist".equals(item.getType()) && !"MusicArtist".equals(item.getType()) && userData!= null && userData.getUnplayedItemCount() !=null && userData.getUnplayedItemCount() > 0) menu.getMenu().add(0, MENU_PLAY_FIRST_UNWATCHED, order++, R.string.lbl_play_first_unwatched);
menu.getMenu().add(0, MENU_PLAY, order++, item.getIsFolder() ? R.string.lbl_play_all : R.string.lbl_play);
if (item.getIsFolder()) menu.getMenu().add(0, MENU_PLAY_SHUFFLE, order++, R.string.lbl_shuffle_all);
}
isMusic = "MusicAlbum".equals(item.getType()) || "MusicArtist".equals(item.getType()) || "Audio".equals(item.getType()) || ("Playlist".equals(item.getType()) && "Audio".equals(item.getMediaType()));
if (isMusic || !item.getIsFolder()) menu.getMenu().add(0, MENU_ADD_QUEUE, order++, R.string.lbl_add_to_queue);
if (isMusic) {
if (!"Playlist".equals(item.getType())) menu.getMenu().add(0, MENU_INSTANT_MIX, order++, R.string.lbl_instant_mix);
} else {
if (userData != null && userData.getPlayed())
menu.getMenu().add(0, MENU_UNMARK_PLAYED, order++, activity.getString(R.string.lbl_mark_unplayed));
else
menu.getMenu().add(0, MENU_MARK_PLAYED, order++, activity.getString(R.string.lbl_mark_played));
}
}
if (userData != null) {
if (userData.getIsFavorite())
menu.getMenu().add(0, MENU_UNMARK_FAVORITE, order++, activity.getString(R.string.lbl_remove_favorite));
else
menu.getMenu().add(0, MENU_MARK_FAVORITE, order++, activity.getString(R.string.lbl_add_favorite));
if (userData.getLikes() == null) {
menu.getMenu().add(0, MENU_LIKE, order++, activity.getString(R.string.lbl_like));
menu.getMenu().add(0, MENU_DISLIKE, order++, activity.getString(R.string.lbl_dislike));
} else if (userData.getLikes()) {
menu.getMenu().add(0, MENU_UNLIKE, order++, activity.getString(R.string.lbl_unlike));
menu.getMenu().add(0, MENU_DISLIKE, order++, activity.getString(R.string.lbl_dislike));
} else {
menu.getMenu().add(0, MENU_LIKE, order++, activity.getString(R.string.lbl_like));
menu.getMenu().add(0, MENU_UNDISLIKE, order++, activity.getString(R.string.lbl_remove_dislike));
}
}
//Not sure I like this but I either duplicate processing with in-line events or do this and
// use a single event handler
mCurrentItem = item;
mCurrentRowItemNdx = rowItem.getIndex();
mCurrentItemId = item.getId();
mCurrentActivity = activity;
currentItemIsFolder = item.getIsFolder();
menu.setOnMenuItemClickListener(menuItemClickListener);
menu.show();
}
private static void createPlayMenu(BaseItemDto item, boolean isFolder, boolean isMusic, BaseActivity activity) {
PopupMenu menu = Utils.createPopupMenu(activity, activity.getCurrentFocus(), Gravity.RIGHT);
int order = 0;
if (!isMusic && !"Playlist".equals(item.getType())) menu.getMenu().add(0, MENU_PLAY_FIRST_UNWATCHED, order++, R.string.lbl_play_first_unwatched);
menu.getMenu().add(0, MENU_PLAY, order++, R.string.lbl_play_all);
menu.getMenu().add(0, MENU_PLAY_SHUFFLE, order++, R.string.lbl_shuffle_all);
if (isMusic) {
menu.getMenu().add(0, MENU_ADD_QUEUE, order, R.string.lbl_add_to_queue);
}
//Not sure I like this but I either duplicate processing with in-line events or do this and
// use a single event handler
mCurrentItem = item;
mCurrentItemId = item.getId();
mCurrentActivity = activity;
currentItemIsFolder = isFolder;
menu.setOnMenuItemClickListener(menuItemClickListener);
menu.show();
}
private static PopupMenu.OnMenuItemClickListener menuItemClickListener = new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_PLAY:
if (mCurrentItemId.equals(ItemListActivity.FAV_SONGS)) {
Utils.play(mCurrentItem, 0, false, mCurrentActivity);
} else {
Utils.retrieveAndPlay(mCurrentItemId, false, mCurrentActivity);
}
return true;
case MENU_PLAY_SHUFFLE:
if (mCurrentItemId.equals(ItemListActivity.FAV_SONGS)) {
Utils.play(mCurrentItem, 0, false, mCurrentActivity);
} else {
Utils.retrieveAndPlay(mCurrentItemId, true, mCurrentActivity);
}
return true;
case MENU_ADD_QUEUE:
if (isMusic) {
Utils.getItemsToPlay(mCurrentItem, false, false, new Response<List<BaseItemDto>>() {
@Override
public void onResponse(List<BaseItemDto> response) {
MediaManager.addToAudioQueue(response);
}
@Override
public void onError(Exception exception) {
Utils.showToast(mCurrentActivity, R.string.msg_cannot_play_time);
}
});
} else {
TvApp.getApplication().getApiClient().GetItemAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), new Response<BaseItemDto>() {
@Override
public void onResponse(BaseItemDto response) {
MediaManager.addToVideoQueue(response);
}
@Override
public void onError(Exception exception) {
Utils.showToast(mCurrentActivity, R.string.msg_cannot_play_time);
}
});
}
return true;
case MENU_PLAY_FIRST_UNWATCHED:
StdItemQuery query = new StdItemQuery();
query.setParentId(mCurrentItemId);
query.setRecursive(true);
query.setIsVirtualUnaired(false);
query.setIsMissing(false);
query.setSortBy(new String[]{"SortName"});
query.setSortOrder(SortOrder.Ascending);
query.setLimit(1);
query.setExcludeItemTypes(new String[] {"Series","Season","Folder","MusicAlbum","Playlist","BoxSet"});
query.setFilters(new ItemFilter[] {ItemFilter.IsUnplayed});
TvApp.getApplication().getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
@Override
public void onResponse(ItemsResult response) {
if (response.getTotalRecordCount() == 0) {
Utils.showToast(mCurrentActivity, "No items to play");
} else {
Utils.retrieveAndPlay(response.getItems()[0].getId(), false, mCurrentActivity);
}
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error trying to play first unwatched", exception);
Utils.showToast(mCurrentActivity, R.string.msg_video_playback_error);
}
});
return true;
case MENU_MARK_FAVORITE:
toggleFavorite(true);
return true;
case MENU_UNMARK_FAVORITE:
toggleFavorite(false);
return true;
case MENU_MARK_PLAYED:
if (currentItemIsFolder) {
// confirm
new AlertDialog.Builder(mCurrentActivity)
.setTitle(R.string.lbl_mark_played)
.setMessage(mCurrentActivity.getString(R.string.lbl_confirm_mark_watched))
.setNegativeButton(mCurrentActivity.getString(R.string.lbl_no), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setPositiveButton(mCurrentActivity.getString(R.string.lbl_yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
markPlayed();
}
}).show();
} else {
markPlayed();
}
return true;
case MENU_UNMARK_PLAYED:
if (currentItemIsFolder) {
// confirm
new AlertDialog.Builder(mCurrentActivity)
.setTitle(R.string.lbl_mark_unplayed)
.setMessage(mCurrentActivity.getString(R.string.lbl_confirm_mark_unwatched))
.setNegativeButton(mCurrentActivity.getString(R.string.lbl_no), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).setPositiveButton(mCurrentActivity.getString(R.string.lbl_yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
markUnplayed();
}
}).show();
} else {
markUnplayed();
}
return true;
case MENU_LIKE:
toggleLikes(true);
return true;
case MENU_DISLIKE:
toggleLikes(false);
return true;
case MENU_UNLIKE:
case MENU_UNDISLIKE:
toggleLikes(null);
return true;
case MENU_GOTO_NOW_PLAYING:
Intent nowPlaying = new Intent(TvApp.getApplication(), AudioNowPlayingActivity.class);
mCurrentActivity.startActivity(nowPlaying);
return true;
case MENU_REMOVE_FROM_QUEUE:
MediaManager.removeFromAudioQueue(mCurrentRowItemNdx);
return true;
case MENU_ADVANCE_QUEUE:
MediaManager.playFrom(mCurrentRowItemNdx);
return true;
case MENU_INSTANT_MIX:
Utils.Beep();
Utils.playInstantMix(mCurrentItemId);
return true;
}
return false;
}
};
private static void markPlayed() {
TvApp.getApplication().getApiClient().MarkPlayedAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), null, new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto response) {
mCurrentActivity.sendMessage(CustomMessage.RefreshCurrentItem);
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error setting played status", exception);
Utils.showToast(mCurrentActivity, "Error setting played status");
}
});
}
private static void markUnplayed() {
TvApp.getApplication().getApiClient().MarkUnplayedAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto response) {
mCurrentActivity.sendMessage(CustomMessage.RefreshCurrentItem);
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error setting played status", exception);
Utils.showToast(mCurrentActivity, "Error setting played status");
}
});
}
private static void toggleFavorite(boolean fav) {
TvApp.getApplication().getApiClient().UpdateFavoriteStatusAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), fav, new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto response) {
mCurrentActivity.sendMessage(CustomMessage.RefreshCurrentItem);
TvApp.getApplication().setLastFavoriteUpdate(System.currentTimeMillis());
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error setting favorite status", exception);
Utils.showToast(mCurrentActivity, "Error setting favorite status");
}
});
}
private static void toggleLikes(Boolean likes) {
if (likes == null) {
TvApp.getApplication().getApiClient().ClearUserItemRatingAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto response) {
mCurrentActivity.sendMessage(CustomMessage.RefreshCurrentItem);
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error clearing like status", exception);
Utils.showToast(mCurrentActivity, "Error clearing like status");
}
});
} else {
TvApp.getApplication().getApiClient().UpdateUserItemRatingAsync(mCurrentItemId, TvApp.getApplication().getCurrentUser().getId(), likes, new Response<UserItemDataDto>() {
@Override
public void onResponse(UserItemDataDto response) {
mCurrentActivity.sendMessage(CustomMessage.RefreshCurrentItem);
}
@Override
public void onError(Exception exception) {
TvApp.getApplication().getLogger().ErrorException("Error setting like status", exception);
Utils.showToast(mCurrentActivity, "Error setting like status");
}
});
}
}
}