/* * Copyright (C) 2014 The Android Open Source Project * * 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. */ package com.sregg.android.tv.spotifyPlayer.fragments; import android.content.Intent; import android.os.Bundle; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; import android.support.v17.leanback.widget.OnItemViewClickedListener; import android.support.v17.leanback.widget.OnItemViewSelectedListener; import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; import android.text.format.DateFormat; import android.util.Log; import android.view.View; import com.squareup.otto.Subscribe; import com.sregg.android.tv.spotifyPlayer.BusProvider; import com.sregg.android.tv.spotifyPlayer.Constants; import com.sregg.android.tv.spotifyPlayer.R; import com.sregg.android.tv.spotifyPlayer.SpotifyTvApplication; import com.sregg.android.tv.spotifyPlayer.activities.NowPlayingActivity; import com.sregg.android.tv.spotifyPlayer.activities.SearchActivity; import com.sregg.android.tv.spotifyPlayer.adapters.PagingAdapter; import com.sregg.android.tv.spotifyPlayer.controllers.SpotifyPlayerController; import com.sregg.android.tv.spotifyPlayer.enums.Control; import com.sregg.android.tv.spotifyPlayer.events.ContentState; import com.sregg.android.tv.spotifyPlayer.events.OnTrackChanged; import com.sregg.android.tv.spotifyPlayer.presenters.AlbumCardPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.ArtistCardPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.CategoryCardPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.ControlPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.PlaylistCardPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.PlaylistSimpleCardPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.SettingPresenter; import com.sregg.android.tv.spotifyPlayer.presenters.TrackCardPresenter; import com.sregg.android.tv.spotifyPlayer.settings.CustomizeUiSetting; import com.sregg.android.tv.spotifyPlayer.settings.LastFmSetting; import com.sregg.android.tv.spotifyPlayer.settings.QualitySetting; import com.sregg.android.tv.spotifyPlayer.settings.Setting; import com.sregg.android.tv.spotifyPlayer.settings.UserPreferences; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import kaaes.spotify.webapi.android.SpotifyService; import kaaes.spotify.webapi.android.models.Album; import kaaes.spotify.webapi.android.models.ArtistSimple; import kaaes.spotify.webapi.android.models.CategoriesPager; import kaaes.spotify.webapi.android.models.FeaturedPlaylists; import kaaes.spotify.webapi.android.models.NewReleases; import kaaes.spotify.webapi.android.models.Pager; import kaaes.spotify.webapi.android.models.PlaylistSimple; import kaaes.spotify.webapi.android.models.SavedAlbum; import kaaes.spotify.webapi.android.models.SavedTrack; import kaaes.spotify.webapi.android.models.Track; import kaaes.spotify.webapi.android.models.TrackSimple; import retrofit.Callback; import retrofit.RetrofitError; import retrofit.client.Response; public class MainFragment extends BrowseFragment { private static final String TAG = "MainFragment"; private ArrayObjectAdapter mNewReleasesAdapter = new ArrayObjectAdapter(new AlbumCardPresenter()); private ArrayObjectAdapter mNowPlayingAdapter = new ArrayObjectAdapter(new TrackCardPresenter()); private ArrayObjectAdapter mFeaturedPlaylistsAdapter = new ArrayObjectAdapter(new PlaylistSimpleCardPresenter()); private ArrayObjectAdapter mCategoriesAdapter = new ArrayObjectAdapter(new CategoryCardPresenter()); private PagingAdapter mPlaylistsAdapter; private PagingAdapter mSavedAlbumsAdapter; private PagingAdapter mSavedSongsAdapter; private ArrayObjectAdapter mSavedArtistsAdapter = new ArrayObjectAdapter(new ArtistCardPresenter()); private ArrayObjectAdapter mRowsAdapter; private HeaderItem mNowPlayingHeader; private ListRow mNowPlayingListRow; private boolean mPlaylistsLoading; private boolean mMyAlbumsLoading; private boolean mMySongsLoading; private ArrayList<String> allArtistUris; @Override public void onActivityCreated(Bundle savedInstanceState) { Log.i(TAG, "onCreate"); super.onActivityCreated(savedInstanceState); setupUIElements(); setupEventListeners(); setupSections(); } private void setupSections() { setupMainAdapter(); setupNowPlaying(); setupFeaturedPlaylists(); setupNewReleases(); setupCategories(); setupUserLibraryRows(); loadControlsRow(); loadSettingsRow(); setAdapter(mRowsAdapter); } @Subscribe public void onCustomizeUiSettingChanged(CustomizeUiSetting.OnCustomizeUiSettingChanged event) { setupSections(); } private void setupMainAdapter() { mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter()); } private void setupUIElements() { setTitle(getString(R.string.browse_title)); // over title setHeadersState(HEADERS_ENABLED); setHeadersTransitionOnBackEnabled(true); // set fastLane (or headers) background color setBrandColor(getResources().getColor(R.color.fastlane_background)); // set search icon color setSearchAffordanceColor(getResources().getColor(R.color.search_opaque)); } private void setupEventListeners() { setOnSearchClickedListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(getActivity(), SearchActivity.class); startActivity(intent); } }); setOnItemViewClickedListener(new OnItemViewClickedListener() { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { if (row.getHeaderItem() == mNowPlayingHeader) { startActivity(new Intent(getActivity(), NowPlayingActivity.class)); } else if (item instanceof Setting) { ((Setting) item).onClick(getActivity()); } else if (item instanceof Control) { SpotifyTvApplication.getInstance().getSpotifyPlayerController().onControlClick(((Control) item)); } else if (item instanceof Track) { String trackUri = ((Track) item).uri; SpotifyPlayerController spotifyPlayerController = SpotifyTvApplication.getInstance().getSpotifyPlayerController(); if (spotifyPlayerController.getPlayingState().isCurrentTrack(trackUri)) { spotifyPlayerController.togglePauseResume(); } else { // get song and following ones List<TrackSimple> tracks = new ArrayList<TrackSimple>(); List<String> trackUris = new ArrayList<>(); for (int i = mSavedSongsAdapter.indexOf(item); i < mSavedSongsAdapter.size() && i < Constants.MAX_SONGS_PLAYED; i++) { tracks.add((TrackSimple) mSavedSongsAdapter.get(i)); trackUris.add(((Track) mSavedSongsAdapter.get(i)).uri); } spotifyPlayerController.play(trackUri, trackUris, tracks); } } else { SpotifyTvApplication.getInstance().launchDetailScreen(getActivity(), item); } } }); setOnItemViewSelectedListener(new OnItemViewSelectedListener() { @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { if (row instanceof ListRow && ((ListRow) row).getAdapter() instanceof PagingAdapter) { PagingAdapter pagingAdapter = (PagingAdapter) ((ListRow) row).getAdapter(); pagingAdapter.onItemSelected(item); } } }); } private boolean isSectionEnabled(int sectionResId) { return UserPreferences.getInstance(getActivity()).isSectionEnabled(getString(sectionResId)); } private SpotifyService getSpotifyService() { return SpotifyTvApplication.getInstance().getSpotifyService(); } private void setupNowPlaying() { mNowPlayingHeader = new HeaderItem(0, getString(R.string.now_playing)); TrackSimple currentTrack = SpotifyTvApplication.getInstance().getSpotifyPlayerController().getPlayingState().getCurrentTrack(); if (currentTrack != null) { mNowPlayingAdapter.removeItems(0, mNowPlayingAdapter.size()); mNowPlayingAdapter.add(currentTrack); mNowPlayingListRow = new ListRow(mNowPlayingHeader, mNowPlayingAdapter); mRowsAdapter.add(0, mNowPlayingListRow); } else { mNowPlayingListRow = null; } } private void setupFeaturedPlaylists() { if (isSectionEnabled(R.string.featured_playlists)) { HeaderItem featuredPlaylistsHeader = new HeaderItem(0, getString(R.string.featured_playlists)); mRowsAdapter.add(new ListRow(featuredPlaylistsHeader, mFeaturedPlaylistsAdapter)); loadFeaturedPlaylists(); } } private void loadFeaturedPlaylists() { Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.COUNTRY, SpotifyTvApplication.getCurrentUserCountry()); options.put("timestamp", DateFormat.format("yyyy-MM-dd'T'hh:mm:ss", new Date())); getSpotifyService().getFeaturedPlaylists(options, new Callback<FeaturedPlaylists>() { @Override public void success(FeaturedPlaylists featuredPlaylists, Response response) { mFeaturedPlaylistsAdapter.addAll(0, featuredPlaylists.playlists.items); } @Override public void failure(RetrofitError error) { } }); } private void setupNewReleases() { if (isSectionEnabled(R.string.new_releases)) { HeaderItem newReleasesHeader = new HeaderItem(0, getString(R.string.new_releases)); mRowsAdapter.add(new ListRow(newReleasesHeader, mNewReleasesAdapter)); loadNewReleases(); } } private void loadNewReleases() { Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.COUNTRY, SpotifyTvApplication.getCurrentUserCountry()); getSpotifyService().getNewReleases(options, new Callback<NewReleases>() { @Override public void success(NewReleases newReleases, Response response) { mNewReleasesAdapter.addAll(0, newReleases.albums.items); } @Override public void failure(RetrofitError error) { } }); } private void setupCategories() { if (isSectionEnabled(R.string.categories)) { HeaderItem newReleasesHeader = new HeaderItem(0, getString(R.string.categories)); mRowsAdapter.add(new ListRow(newReleasesHeader, mCategoriesAdapter)); loadCategories(); } } private void loadCategories() { Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.COUNTRY, SpotifyTvApplication.getCurrentUserCountry()); getSpotifyService().getCategories(options, new Callback<CategoriesPager>() { @Override public void success(CategoriesPager categoriesPager, Response response) { mCategoriesAdapter.addAll(0, categoriesPager.categories.items); } @Override public void failure(RetrofitError error) { } }); } private void setupUserLibraryRows() { // playlist row if (isSectionEnabled(R.string.my_playlists)) { mPlaylistsAdapter = new PagingAdapter(new PlaylistCardPresenter()) { @Override public void onLoadMore(int offset) { loadPlaylists(offset); } }; HeaderItem playListHeader = new HeaderItem(0, getString(R.string.my_playlists)); mRowsAdapter.add(new ListRow(playListHeader, mPlaylistsAdapter)); loadPlaylists(); } // Albums row boolean showMyAlbums = isSectionEnabled(R.string.my_albums); if (showMyAlbums) { mSavedAlbumsAdapter = new PagingAdapter(new AlbumCardPresenter()) { @Override public void onLoadMore(int offset) { loadMyAlbums(offset); } }; HeaderItem albumsHeader = new HeaderItem(0, getString(R.string.my_albums)); mRowsAdapter.add(new ListRow(albumsHeader, mSavedAlbumsAdapter)); loadMyAlbums(); } // Artists row boolean showMyArtists = isSectionEnabled(R.string.my_artists); if (showMyArtists) { HeaderItem artistsHeader = new HeaderItem(0, getString(R.string.my_artists)); mRowsAdapter.add(new ListRow(artistsHeader, mSavedArtistsAdapter)); } // Songs row boolean showMySongs = isSectionEnabled(R.string.my_songs); if (showMySongs) { mSavedSongsAdapter = new PagingAdapter(new TrackCardPresenter()) { @Override public void onLoadMore(int offset) { loadMySongs(offset); } }; HeaderItem songsHeader = new HeaderItem(0, getString(R.string.my_songs)); mRowsAdapter.add(new ListRow(songsHeader, mSavedSongsAdapter)); loadMySongs(); } } private void loadPlaylists() { loadPlaylists(0); } private void loadPlaylists(int offset) { if (mPlaylistsLoading){ return; } mPlaylistsLoading = true; Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.OFFSET, offset); options.put(SpotifyService.LIMIT, Constants.PAGE_LIMIT); getSpotifyService().getMyPlaylists(options, new Callback<Pager<PlaylistSimple>>() { @Override public void success(Pager<PlaylistSimple> playlistPager, Response response) { mPlaylistsAdapter.addAll(playlistPager.total, mPlaylistsAdapter.size(), playlistPager.items); mPlaylistsLoading = false; } @Override public void failure(RetrofitError error) { mPlaylistsLoading = false; } }); } private void loadMyAlbums() { loadMyAlbums(0); } private void loadMyAlbums(final int offset) { if (mMyAlbumsLoading){ return; } mMyAlbumsLoading = true; Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.OFFSET, offset); options.put(SpotifyService.LIMIT, Constants.PAGE_LIMIT); getSpotifyService().getMySavedAlbums(options, new Callback<Pager<SavedAlbum>>() { @Override public void success(Pager<SavedAlbum> savedAlbumPager, Response response) { List<Album> albums = new ArrayList<>(savedAlbumPager.items.size()); List<ArtistSimple> artists = new ArrayList<>(savedAlbumPager.items.size()); // keep track of all artists to avoid duplicates if (offset == 0) { allArtistUris = new ArrayList<>(savedAlbumPager.items.size()); } for (SavedAlbum savedAlbum : savedAlbumPager.items) { albums.add(savedAlbum.album); for (ArtistSimple artist : savedAlbum.album.artists) { if (!allArtistUris.contains(artist.id)) { artists.add(artist); allArtistUris.add(artist.id); } } } mSavedAlbumsAdapter.addAll(savedAlbumPager.total, mSavedAlbumsAdapter.size(), albums); mSavedArtistsAdapter.addAll(mSavedArtistsAdapter.size(), artists); mMyAlbumsLoading = false; } @Override public void failure(RetrofitError error) { mMyAlbumsLoading = false; } }); } private void loadMySongs() { loadMySongs(0); } private void loadMySongs(int offset) { if (mMySongsLoading){ return; } mMySongsLoading = true; Map<String, Object> options = new HashMap<>(); options.put(SpotifyService.OFFSET, offset); options.put(SpotifyService.LIMIT, Constants.PAGE_LIMIT); getSpotifyService().getMySavedTracks(options, new Callback<Pager<SavedTrack>>() { @Override public void success(Pager<SavedTrack> savedTrackPager, Response response) { List<Track> tracks = new ArrayList<>(savedTrackPager.items.size()); for (SavedTrack savedTrack : savedTrackPager.items) { tracks.add(savedTrack.track); } mSavedSongsAdapter.addAll(savedTrackPager.total, mSavedSongsAdapter.size(), tracks); mMySongsLoading = false; } @Override public void failure(RetrofitError error) { mMySongsLoading = false; } }); } private void loadControlsRow() { HeaderItem controlsHeader = new HeaderItem(getString(R.string.controls)); ControlPresenter controlPresenter = new ControlPresenter(); ArrayObjectAdapter controlsAdapter = new ArrayObjectAdapter(controlPresenter); controlsAdapter.add(Control.SHUFFLE); controlsAdapter.add(Control.PREVIOUS); controlsAdapter.add(Control.PLAY); controlsAdapter.add(Control.PAUSE); controlsAdapter.add(Control.STOP); controlsAdapter.add(Control.NEXT); mRowsAdapter.add(new ListRow(controlsHeader, controlsAdapter)); } private void loadSettingsRow() { HeaderItem settingsHeader = new HeaderItem(getString(R.string.settings)); SettingPresenter settingPresenter = new SettingPresenter(); ArrayObjectAdapter settingsAdapter = new ArrayObjectAdapter(settingPresenter); settingsAdapter.add(new QualitySetting()); settingsAdapter.add(new LastFmSetting()); settingsAdapter.add(new CustomizeUiSetting()); mRowsAdapter.add(new ListRow(settingsHeader, settingsAdapter)); } @SuppressWarnings("unused") @Subscribe public void onTrackChanged(OnTrackChanged onTrackChanged) { ContentState contentState = onTrackChanged.getPlayingState(); mNowPlayingAdapter.removeItems(0, mNowPlayingAdapter.size()); if (contentState.getCurrentTrack() != null) { mNowPlayingAdapter.add(0, contentState.getCurrentTrack()); } if (mNowPlayingListRow == null) { mNowPlayingListRow = new ListRow(mNowPlayingHeader, mNowPlayingAdapter); mRowsAdapter.add(0, mNowPlayingListRow); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); BusProvider.getInstance().register(this); } @Override public void onDestroy() { BusProvider.getInstance().unregister(this); super.onDestroy(); } }