diff --git a/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java b/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java index 1cc0e46..65aded4 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java +++ b/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java @@ -19,6 +19,7 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.SharedElementCallback; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; @@ -66,6 +67,8 @@ public class MusicActivity extends BaseActivity private NavigationDrawerFragment navigationDrawerFragment; + private MusicListFragment musicListFragment; + private boolean clearSharedElements; @TargetApi(21) @@ -80,7 +83,7 @@ public class MusicActivity extends BaseActivity navigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); if (savedInstanceState == null) { - MusicListFragment musicListFragment = new MusicListFragment(); + musicListFragment = new MusicListFragment(); // Setup animations if (Utils.isLollipopOrLater()) { @@ -88,6 +91,16 @@ public class MusicActivity extends BaseActivity musicListFragment.setReenterTransition(TransitionInflater .from(this) .inflateTransition(android.R.transition.fade)); + musicListFragment.setExitSharedElementCallback(new SharedElementCallback() { + @Override + public void onMapSharedElements(List names, Map sharedElements) { + if (clearSharedElements) { + names.clear(); + sharedElements.clear(); + clearSharedElements = false; + } + } + }); } getSupportFragmentManager() .beginTransaction() @@ -360,20 +373,46 @@ public class MusicActivity extends BaseActivity } @TargetApi(21) - public void onMusicVideoSelected(int musicVideoId, String musicVideoTitle) { - selectedMusicVideoId = musicVideoId; - selectedMusicVideoTitle = musicVideoTitle; + public void onMusicVideoSelected(MusicVideoListFragment.ViewHolder vh) { + selectedMusicVideoId = vh.musicVideoId; + selectedMusicVideoTitle = vh.musicVideoTitle; // Replace list fragment - MusicVideoDetailsFragment detailsFragment = MusicVideoDetailsFragment.newInstance(musicVideoId); + final MusicVideoDetailsFragment detailsFragment = MusicVideoDetailsFragment.newInstance(vh); FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction(); // Set up transitions if (Utils.isLollipopOrLater()) { + android.support.v4.app.SharedElementCallback seCallback = new android.support.v4.app.SharedElementCallback() { + @Override + public void onMapSharedElements(List names, Map sharedElements) { + //On returning onMapSharedElements for the exiting fragment is called before the onMapSharedElements + // for the reentering fragment. We use this to determine if we are returning and if + // we should clear the shared element lists. Note that, clearing must be done in the reentering fragment + // as this is called last. Otherwise it the app will crash during transition setup. Not sure, but might + // be a v4 support package bug. + if (detailsFragment.isVisible()) { + View sharedView = detailsFragment.getSharedElement(); + if (sharedView == null) { // shared element not visible + LogUtils.LOGD(TAG, "onMusicVideoSelected: setting clearedSharedElements to true"); + clearSharedElements = true; + } + } + } + }; + detailsFragment.setEnterSharedElementCallback(seCallback); + detailsFragment.setEnterTransition(TransitionInflater .from(this) .inflateTransition(R.transition.media_details)); detailsFragment.setReturnTransition(null); + + Transition changeImageTransition = TransitionInflater.from( + this).inflateTransition(R.transition.change_image); + detailsFragment.setSharedElementReturnTransition(changeImageTransition); + detailsFragment.setSharedElementEnterTransition(changeImageTransition); + + fragTrans.addSharedElement(vh.artView, vh.artView.getTransitionName()); } else { fragTrans.setCustomAnimations(R.anim.fragment_details_enter, 0, R.anim.fragment_list_popenter, 0); @@ -382,6 +421,6 @@ public class MusicActivity extends BaseActivity fragTrans.replace(R.id.fragment_container, detailsFragment) .addToBackStack(null) .commit(); - setupActionBar(null, null, null, musicVideoTitle); + setupActionBar(null, null, null, selectedMusicVideoTitle); } } diff --git a/app/src/main/java/org/xbmc/kore/ui/MusicVideoDetailsFragment.java b/app/src/main/java/org/xbmc/kore/ui/MusicVideoDetailsFragment.java index 3dbfb67..fef2c6d 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MusicVideoDetailsFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/MusicVideoDetailsFragment.java @@ -15,6 +15,7 @@ */ package org.xbmc.kore.ui; +import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.res.Resources; @@ -55,6 +56,7 @@ import org.xbmc.kore.service.LibrarySyncService; import org.xbmc.kore.utils.FileDownloadHelper; import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.UIUtils; +import org.xbmc.kore.utils.Utils; import java.io.File; import java.util.ArrayList; @@ -70,7 +72,15 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment implements LoaderManager.LoaderCallbacks { private static final String TAG = LogUtils.makeLogTag(MusicVideoDetailsFragment.class); - public static final String MUSICVIDEOID = "music_video_id"; + public static final String BUNDLE_KEY_ID = "music_video_id"; + public static final String BUNDLE_KEY_ALBUM = "album"; + public static final String POSTER_TRANS_NAME = "POSTER_TRANS_NAME"; + public static final String BUNDLE_KEY_ARTIST = "artist"; + public static final String BUNDLE_KEY_TITLE = "title"; + public static final String BUNDLE_KEY_GENRES = "genre"; + public static final String BUNDLE_KEY_YEAR = "year"; + public static final String BUNDLE_KEY_PLOT = "plot"; + public static final String BUNDLE_KEY_RUNTIME = "runtime"; // Loader IDs private static final int LOADER_MUSIC_VIDEO = 0; @@ -114,18 +124,32 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment /** * Create a new instance of this, initialized to show the video musicVideoId */ - public static MusicVideoDetailsFragment newInstance(int musicVideoId) { + @TargetApi(21) + public static MusicVideoDetailsFragment newInstance(MusicVideoListFragment.ViewHolder vh) { MusicVideoDetailsFragment fragment = new MusicVideoDetailsFragment(); Bundle args = new Bundle(); - args.putInt(MUSICVIDEOID, musicVideoId); + args.putInt(BUNDLE_KEY_ID, vh.musicVideoId); + args.putString(BUNDLE_KEY_TITLE, vh.musicVideoTitle); + args.putString(BUNDLE_KEY_ALBUM, vh.album); + args.putString(BUNDLE_KEY_ARTIST, vh.artist); + args.putString(BUNDLE_KEY_GENRES, vh.genres); + args.putString(BUNDLE_KEY_PLOT, vh.plot); + args.putInt(BUNDLE_KEY_RUNTIME, vh.runtime); + args.putInt(BUNDLE_KEY_YEAR, vh.year); + + if( Utils.isLollipopOrLater()) { + args.putString(POSTER_TRANS_NAME, vh.artView.getTransitionName()); + } fragment.setArguments(args); return fragment; } + @TargetApi(21) @Override protected View createView(LayoutInflater inflater, ViewGroup container) { - musicVideoId = getArguments().getInt(MUSICVIDEOID, -1); + Bundle bundle = getArguments(); + musicVideoId = bundle.getInt(BUNDLE_KEY_ID, -1); if (musicVideoId == -1) { // There's nothing to show @@ -152,6 +176,16 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment FloatingActionButton fab = (FloatingActionButton)fabButton; fab.attachToScrollView((ObservableScrollView) mediaPanel); + mediaTitle.setText(bundle.getString(BUNDLE_KEY_TITLE)); + setMediaUndertitle(bundle.getString(BUNDLE_KEY_ARTIST), bundle.getString(BUNDLE_KEY_ALBUM)); + setMediaYear(bundle.getInt(BUNDLE_KEY_RUNTIME), bundle.getInt(BUNDLE_KEY_YEAR)); + mediaGenres.setText(bundle.getString(BUNDLE_KEY_GENRES)); + mediaDescription.setText(bundle.getString(BUNDLE_KEY_PLOT)); + + if(Utils.isLollipopOrLater()) { + mediaPoster.setTransitionName(bundle.getString(POSTER_TRANS_NAME)); + } + // Pad main content view to overlap with bottom system bar // UIUtils.setPaddingForSystemBars(getActivity(), mediaPanel, false, false, true); // mediaPanel.setClipToPadding(false); @@ -380,16 +414,11 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment cursor.moveToFirst(); String musicVideoTitle = cursor.getString(MusicVideoDetailsQuery.TITLE); mediaTitle.setText(musicVideoTitle); - String artistAlbum = cursor.getString(MusicVideoDetailsQuery.ARTIST) + " | " + - cursor.getString(MusicVideoDetailsQuery.ALBUM); - mediaUndertitle.setText(artistAlbum); - int runtime = cursor.getInt(MusicVideoDetailsQuery.RUNTIME); - String durationYear = runtime > 0 ? - UIUtils.formatTime(runtime) + " | " + - String.valueOf(cursor.getInt(MusicVideoDetailsQuery.YEAR)) : - String.valueOf(cursor.getInt(MusicVideoDetailsQuery.YEAR)); - mediaYear.setText(durationYear); + setMediaUndertitle(cursor.getString(MusicVideoDetailsQuery.ARTIST), cursor.getString(MusicVideoDetailsQuery.ALBUM)); + + setMediaYear(cursor.getInt(MusicVideoDetailsQuery.RUNTIME), cursor.getInt(MusicVideoDetailsQuery.YEAR)); + mediaGenres.setText(cursor.getString(MusicVideoDetailsQuery.GENRES)); mediaDescription.setText(cursor.getString(MusicVideoDetailsQuery.PLOT)); @@ -404,41 +433,20 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment int artHeight = resources.getDimensionPixelOffset(R.dimen.now_playing_art_height), artWidth = displayMetrics.widthPixels; - if (!TextUtils.isEmpty(fanart)) { - int posterWidth = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_width); - int posterHeight = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_heigth); - mediaPoster.setVisibility(View.VISIBLE); - UIUtils.loadImageWithCharacterAvatar(getActivity(), getHostManager(), - poster, musicVideoTitle, - mediaPoster, posterWidth, posterHeight); - UIUtils.loadImageIntoImageview(getHostManager(), - fanart, - mediaArt, artWidth, artHeight); - } else { - // No fanart, just present the poster - mediaPoster.setVisibility(View.GONE); - UIUtils.loadImageIntoImageview(getHostManager(), - poster, - mediaArt, artWidth, artHeight); - // Reset padding - int paddingLeft = mediaTitle.getPaddingRight(), - paddingRight = mediaTitle.getPaddingRight(), - paddingTop = mediaTitle.getPaddingTop(), - paddingBottom = mediaTitle.getPaddingBottom(); - mediaTitle.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - mediaUndertitle.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); - } - - - - + int posterWidth = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_width); + int posterHeight = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_width); + UIUtils.loadImageWithCharacterAvatar(getActivity(), getHostManager(), + poster, musicVideoTitle, + mediaPoster, posterWidth, posterHeight); + UIUtils.loadImageIntoImageview(getHostManager(), + TextUtils.isEmpty(fanart)? poster : fanart, + mediaArt, artWidth, artHeight); // Setup download info musicVideoDownloadInfo = new FileDownloadHelper.MusicVideoInfo( musicVideoTitle, cursor.getString(MusicVideoDetailsQuery.FILE)); // Check if downloaded file exists - downloadButton.setVisibility(View.VISIBLE); if (musicVideoDownloadInfo.downloadFileExists()) { Resources.Theme theme = getActivity().getTheme(); TypedArray styledAttributes = theme.obtainStyledAttributes(new int[]{ @@ -452,6 +460,30 @@ public class MusicVideoDetailsFragment extends AbstractDetailsFragment } } + private void setMediaUndertitle(String artist, String album) { + mediaUndertitle.setText(artist + " | " + album); + } + + private void setMediaYear(int runtime, int year) { + String durationYear = runtime > 0 ? + UIUtils.formatTime(runtime) + " | " + + String.valueOf(year) : + String.valueOf(year); + mediaYear.setText(durationYear); + } + + /** + * Returns the shared element if visible + * @return View if visible, null otherwise + */ + public View getSharedElement() { + if (UIUtils.isViewInBounds(mediaPanel, mediaPoster)) { + return mediaPoster; + } + + return null; + } + /** * Video details query parameters. */ diff --git a/app/src/main/java/org/xbmc/kore/ui/MusicVideoListFragment.java b/app/src/main/java/org/xbmc/kore/ui/MusicVideoListFragment.java index 378bc93..66efd11 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MusicVideoListFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/MusicVideoListFragment.java @@ -15,6 +15,7 @@ */ package org.xbmc.kore.ui; +import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.res.Resources; @@ -44,6 +45,7 @@ import org.xbmc.kore.provider.MediaDatabase; import org.xbmc.kore.service.LibrarySyncService; import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.UIUtils; +import org.xbmc.kore.utils.Utils; /** * Fragment that presents the artists list @@ -52,7 +54,7 @@ public class MusicVideoListFragment extends AbstractListFragment { private static final String TAG = LogUtils.makeLogTag(MusicVideoListFragment.class); public interface OnMusicVideoSelectedListener { - public void onMusicVideoSelected(int musicVideoId, String musicVideoTitle); + public void onMusicVideoSelected(ViewHolder vh); } // Activity listener @@ -69,7 +71,7 @@ public class MusicVideoListFragment extends AbstractListFragment { // Get the movie id from the tag ViewHolder tag = (ViewHolder)view.getTag(); // Notify the activity - listenerActivity.onMusicVideoSelected(tag.musicVideoId, tag.musicVideoTitle); + listenerActivity.onMusicVideoSelected(tag); } }; } @@ -141,6 +143,8 @@ public class MusicVideoListFragment extends AbstractListFragment { MediaContract.MusicVideos.THUMBNAIL, MediaContract.MusicVideos.RUNTIME, MediaContract.MusicVideos.GENRES, + MediaContract.MusicVideos.YEAR, + MediaContract.MusicVideos.PLOT, }; String SORT = MediaDatabase.sortCommonTokens(MediaContract.MusicVideos.TITLE) + " ASC"; @@ -153,6 +157,8 @@ public class MusicVideoListFragment extends AbstractListFragment { final int THUMBNAIL = 5; final int RUNTIME = 6; final int GENRES = 7; + final int YEAR = 8; + final int PLOT = 9; } private static class MusicVideosAdapter extends CursorAdapter { @@ -166,10 +172,8 @@ public class MusicVideoListFragment extends AbstractListFragment { // Get the art dimensions Resources resources = context.getResources(); - artWidth = (int)(resources.getDimension(R.dimen.musicvideolist_art_width) / - UIUtils.IMAGE_RESIZE_FACTOR); - artHeight = (int)(resources.getDimension(R.dimen.musicvideolist_art_heigth) / - UIUtils.IMAGE_RESIZE_FACTOR); + artHeight = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_heigth); + artWidth = resources.getDimensionPixelOffset(R.dimen.musicvideodetail_poster_width); } /** {@inheritDoc} */ @@ -190,6 +194,7 @@ public class MusicVideoListFragment extends AbstractListFragment { } /** {@inheritDoc} */ + @TargetApi(21) @Override public void bindView(View view, Context context, Cursor cursor) { final ViewHolder viewHolder = (ViewHolder)view.getTag(); @@ -197,28 +202,37 @@ public class MusicVideoListFragment extends AbstractListFragment { // Save the movie id viewHolder.musicVideoId = cursor.getInt(MusicVideosListQuery.MUSICVIDEOID); viewHolder.musicVideoTitle = cursor.getString(MusicVideosListQuery.TITLE); + viewHolder.album = cursor.getString(MusicVideosListQuery.ALBUM); + viewHolder.artist = cursor.getString(MusicVideosListQuery.ARTIST); + viewHolder.genres = cursor.getString(MusicVideosListQuery.GENRES); + viewHolder.plot = cursor.getString(MusicVideosListQuery.PLOT); + viewHolder.runtime = cursor.getInt(MusicVideosListQuery.RUNTIME); + viewHolder.year = cursor.getInt(MusicVideosListQuery.YEAR); viewHolder.titleView.setText(viewHolder.musicVideoTitle); - String artistAlbum = cursor.getString(MusicVideosListQuery.ARTIST) + " | " + - cursor.getString(MusicVideosListQuery.ALBUM); + String artistAlbum = viewHolder.artist + " | " + + viewHolder.album; viewHolder.artistAlbumView.setText(artistAlbum); - int runtime = cursor.getInt(MusicVideosListQuery.RUNTIME); String durationGenres = - runtime > 0 ? - UIUtils.formatTime(runtime) + " | " + cursor.getString(MusicVideosListQuery.GENRES) : - cursor.getString(MusicVideosListQuery.GENRES); + viewHolder.runtime > 0 ? + UIUtils.formatTime(viewHolder.runtime) + " | " + viewHolder.genres : + viewHolder.genres; viewHolder.durationGenresView.setText(durationGenres); UIUtils.loadImageWithCharacterAvatar(context, hostManager, cursor.getString(MusicVideosListQuery.THUMBNAIL), viewHolder.musicVideoTitle, viewHolder.artView, artWidth, artHeight); + + if(Utils.isLollipopOrLater()) { + viewHolder.artView.setTransitionName("a"+viewHolder.musicVideoId); + } } } /** * View holder pattern */ - private static class ViewHolder { + public static class ViewHolder { TextView titleView; TextView artistAlbumView; TextView durationGenresView; @@ -226,5 +240,11 @@ public class MusicVideoListFragment extends AbstractListFragment { int musicVideoId; String musicVideoTitle; + String artist; + String album; + int runtime; + String genres; + int year; + String plot; } } diff --git a/app/src/main/res/layout/fragment_music_video_details.xml b/app/src/main/res/layout/fragment_music_video_details.xml index 7db02f0..ef36220 100644 --- a/app/src/main/res/layout/fragment_music_video_details.xml +++ b/app/src/main/res/layout/fragment_music_video_details.xml @@ -115,8 +115,7 @@ android:layout_height="match_parent" style="@style/Widget.Button.Borderless" android:src="?attr/iconDownload" - android:contentDescription="@string/download" - android:visibility="gone"/> + android:contentDescription="@string/download"/>