package tv.emby.embyatv.livetv; import android.app.Activity; import android.graphics.Typeface; import android.preference.PreferenceManager; import android.text.format.DateUtils; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.TimeZone; import mediabrowser.apiinteraction.EmptyResponse; import mediabrowser.apiinteraction.Response; import mediabrowser.model.dto.BaseItemDto; import mediabrowser.model.entities.ImageType; import mediabrowser.model.livetv.ChannelInfoDto; import mediabrowser.model.livetv.LiveTvChannelQuery; import mediabrowser.model.livetv.ProgramQuery; import mediabrowser.model.querying.ItemFields; import mediabrowser.model.querying.ItemsResult; import mediabrowser.model.results.ChannelInfoDtoResult; import tv.emby.embyatv.R; import tv.emby.embyatv.TvApp; import tv.emby.embyatv.ui.ProgramGridCell; import tv.emby.embyatv.util.Utils; /** * Created by Eric on 9/4/2015. */ public class TvManager { private static List<ChannelInfoDto> allChannels; private static String[] channelIds; private static HashMap<String, ArrayList<BaseItemDto>> mProgramsDict = new HashMap<>(); private static Calendar needLoadTime; private static Calendar programNeedLoadTime; public static String getLastLiveTvChannel() { return TvApp.getApplication().getSystemPrefs().getString("sys_pref_last_tv_channel", null); } public static void setLastLiveTvChannel(String id) { TvApp.getApplication().getSystemPrefs().edit().putString("sys_pref_prev_tv_channel", TvApp.getApplication().getSystemPrefs().getString("sys_pref_last_tv_channel", null)).commit(); TvApp.getApplication().getSystemPrefs().edit().putString("sys_pref_last_tv_channel", id).commit(); updateLastPlayedDate(id); sortChannels(); } public static String getPrevLiveTvChannel() { return TvApp.getApplication().getSystemPrefs().getString("sys_pref_prev_tv_channel", null); } public static List<ChannelInfoDto> getAllChannels() { return allChannels; } public static void resetChannels() { allChannels = null; } public static int getAllChannelsIndex(String id) { for (int i = 0; i < allChannels.size(); i++) { if (allChannels.get(i).getId().equals(id)) return i; } return -1; } public static ChannelInfoDto getChannel(int ndx) { return allChannels.get(ndx); } public static void updateLastPlayedDate(String channelId) { if (allChannels != null) { int ndx = getAllChannelsIndex(channelId); if (ndx >= 0) { TimeZone timeZone = Calendar.getInstance().getTimeZone(); Date now = new Date(); allChannels.get(ndx).getUserData().setLastPlayedDate(new Date(now.getTime()-timeZone.getRawOffset())); } } } public static void loadAllChannels(final Response<Integer> outerResponse) { //Get channels LiveTvChannelQuery query = new LiveTvChannelQuery(); query.setUserId(TvApp.getApplication().getCurrentUser().getId()); query.setEnableFavoriteSorting(true); query.setAddCurrentProgram(false); TvApp.getApplication().getLogger().Debug("*** About to load channels"); TvApp.getApplication().getApiClient().GetLiveTvChannelsAsync(query, new Response<ChannelInfoDtoResult>() { @Override public void onResponse(final ChannelInfoDtoResult response) { TvApp.getApplication().getLogger().Debug("*** channel query response"); allChannels = new ArrayList<>(); int ndx = 0; if (response.getTotalRecordCount() > 0) { Collections.addAll(allChannels, response.getItems()); } outerResponse.onResponse(sortChannels()); } }); } public static int sortChannels() { int ndx = 0; if (allChannels != null) { //Sort by last played - if selected if (TvApp.getApplication().getPrefs().getBoolean("pref_guide_sort_date", true)) { Collections.sort(allChannels, Collections.reverseOrder(new Comparator<ChannelInfoDto>() { @Override public int compare(ChannelInfoDto lhs, ChannelInfoDto rhs) { long left = lhs.getUserData() == null || lhs.getUserData().getLastPlayedDate() == null ? 0 : lhs.getUserData().getLastPlayedDate().getTime(); long right = rhs.getUserData() == null || rhs.getUserData().getLastPlayedDate() == null ? 0 : rhs.getUserData().getLastPlayedDate().getTime(); long result = left - right; return result == 0 ? 0 : result > 0 ? 1 : -1; } })); } //And fill in channel IDs channelIds = new String[allChannels.size()]; String last = getLastLiveTvChannel(); int i = 0; for (ChannelInfoDto channel : allChannels) { channelIds[i++] = channel.getId(); if (channel.getId().equals(last)) ndx = i; //TvApp.getApplication().getLogger().Debug("Last played for "+channel.getName()+ " is "+channel.getUserData().getLastPlayedDate()); } } return ndx; } public static void getProgramsAsync(int startNdx, int endNdx, Calendar endTime, final EmptyResponse outerResponse) { final Calendar start = new GregorianCalendar(TimeZone.getTimeZone("Z")); start.set(Calendar.MINUTE, start.get(Calendar.MINUTE) >= 30 ? 30 : 0); start.set(Calendar.SECOND, 1); if (needLoadTime == null || start.after(needLoadTime) || !mProgramsDict.containsKey(channelIds[startNdx]) || !mProgramsDict.containsKey(channelIds[endNdx])) { ProgramQuery query = new ProgramQuery(); query.setUserId(TvApp.getApplication().getCurrentUser().getId()); endNdx = endNdx > channelIds.length ? channelIds.length : endNdx+1; //array copy range final ndx is exclusive query.setChannelIds(Arrays.copyOfRange(channelIds, startNdx, endNdx)); query.setEnableImages(false); query.setSortBy(new String[] {"StartDate"}); Calendar end = (Calendar) endTime.clone(); end.setTimeZone(TimeZone.getTimeZone("Z")); end.add(Calendar.SECOND, -1); query.setMaxStartDate(end.getTime()); query.setMinEndDate(start.getTime()); TvApp.getApplication().getLogger().Debug("*** About to get programs"); TvApp.getApplication().getApiClient().GetLiveTvProgramsAsync(query, new Response<ItemsResult>() { @Override public void onResponse(ItemsResult response) { TvApp.getApplication().getLogger().Debug("*** About to build dictionary"); buildProgramsDict(response.getItems(), start); TvApp.getApplication().getLogger().Debug("*** Programs retrieval finished"); outerResponse.onResponse(); } @Override public void onError(Exception exception) { outerResponse.onError(exception); } }); } else { outerResponse.onResponse(); } } private static void buildProgramsDict(BaseItemDto[] programs, Calendar startTime) { mProgramsDict = new HashMap<>(); long start = startTime.getTimeInMillis(); for (BaseItemDto program : programs) { String id = program.getChannelId(); if (!mProgramsDict.containsKey(id)) mProgramsDict.put(id, new ArrayList<BaseItemDto>()); if (Utils.convertToLocalDate(program.getEndDate()).getTime() > start) mProgramsDict.get(id).add(program); } needLoadTime = (Calendar) startTime.clone(); needLoadTime.setTimeZone(TimeZone.getTimeZone("Z")); needLoadTime.add(Calendar.MINUTE, 29); } public static Calendar updateProgramsNeedsLoadTime() { programNeedLoadTime = new GregorianCalendar(TimeZone.getTimeZone("Z")); programNeedLoadTime.set(Calendar.MINUTE, programNeedLoadTime.get(Calendar.MINUTE) >= 30 ? 30 : 0); programNeedLoadTime.set(Calendar.SECOND, 0); return programNeedLoadTime; } public static boolean programsNeedLoad(Calendar now) { return programNeedLoadTime == null || now.after(programNeedLoadTime); } public static List<BaseItemDto> getProgramsForChannel(String channelId, GuideFilters filters) { if (!mProgramsDict.containsKey(channelId)) return new ArrayList<>(); List<BaseItemDto> results = mProgramsDict.get(channelId); boolean passes = filters == null || !filters.any(); if (passes) return results; // There are filters - check them for (BaseItemDto program : results) { passes |= filters.passesFilter(program); } return passes ? results : new ArrayList<BaseItemDto>(); } public static List<BaseItemDto> getProgramsForChannel(String channelId) { return !mProgramsDict.containsKey(channelId) ? new ArrayList<BaseItemDto>() : mProgramsDict.get(channelId); } public static void setTimelineRow(Activity activity, LinearLayout timelineRow, BaseItemDto program) { timelineRow.removeAllViews(); Date local = Utils.convertToLocalDate(program.getStartDate()); TextView on = new TextView(activity); on.setText(activity.getResources().getString(R.string.lbl_on)); timelineRow.addView(on); TextView channel = new TextView(activity); channel.setText(program.getChannelName()); channel.setTypeface(null, Typeface.BOLD); channel.setTextColor(activity.getResources().getColor(android.R.color.holo_blue_light)); timelineRow.addView(channel); TextView datetime = new TextView(activity); datetime.setText(Utils.getFriendlyDate(local)+ " @ "+android.text.format.DateFormat.getTimeFormat(activity).format(local)+ " ("+ DateUtils.getRelativeTimeSpanString(local.getTime())+")"); timelineRow.addView(datetime); } // this makes focus movements more predictable for the grid view public static void setFocusParms(LinearLayout currentRow, LinearLayout otherRow, boolean up) { for (int currentRowNdx = 0; currentRowNdx < currentRow.getChildCount(); currentRowNdx++) { ProgramGridCell cell = (ProgramGridCell) currentRow.getChildAt(currentRowNdx); ProgramGridCell otherCell = getOtherCell(otherRow, cell); if (otherCell != null) { if (up) { cell.setNextFocusUpId(otherCell.getId()); //TvApp.getApplication().getLogger().Debug("Setting up focus for " + cell.getProgram().getName() + " to " + otherCell.getProgram().getName()+"("+otherCell.getId()+")"); } else { cell.setNextFocusDownId(otherCell.getId()); //TvApp.getApplication().getLogger().Debug("Setting down focus for " + cell.getProgram().getName() + " to " + otherCell.getProgram().getName()); } } } } private static ProgramGridCell getOtherCell(LinearLayout otherRow, ProgramGridCell cell) { // find first cell in other row where our left edge is within its body (will be first one who's right edge is greater than our left) for (int otherRowNdx = 0; otherRowNdx < otherRow.getChildCount(); otherRowNdx++) { ProgramGridCell otherCell = (ProgramGridCell) otherRow.getChildAt(otherRowNdx); if (otherCell.getProgram().getEndDate() != null && cell.getProgram().getStartDate() != null && otherCell.getProgram().getEndDate().getTime() > cell.getProgram().getStartDate().getTime()) { return otherCell; } } return null; } }