diff --git a/app/src/main/java/org/xbmc/kore/ui/AlbumDetailsFragment.java b/app/src/main/java/org/xbmc/kore/ui/AlbumDetailsFragment.java index 45f8c60..9333406 100644 --- a/app/src/main/java/org/xbmc/kore/ui/AlbumDetailsFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/AlbumDetailsFragment.java @@ -669,6 +669,18 @@ public class AlbumDetailsFragment extends Fragment } } + /** + * Returns the shared element if visible + * @return View if visible, null otherwise + */ + public View getSharedElement() { + if (UIUtils.isViewInBounds(mediaPanel, mediaPoster)) { + return mediaPoster; + } + + return null; + } + /** * Album details query parameters. */ diff --git a/app/src/main/java/org/xbmc/kore/ui/MovieDetailsFragment.java b/app/src/main/java/org/xbmc/kore/ui/MovieDetailsFragment.java index e657384..0c40f61 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MovieDetailsFragment.java +++ b/app/src/main/java/org/xbmc/kore/ui/MovieDetailsFragment.java @@ -201,7 +201,7 @@ public class MovieDetailsFragment extends AbstractDetailsFragment // Pad main content view to overlap with bottom system bar // UIUtils.setPaddingForSystemBars(getActivity(), mediaPanel, false, false, true); // mediaPanel.setClipToPadding(false); - + return root; } @@ -628,6 +628,18 @@ public class MovieDetailsFragment extends AbstractDetailsFragment } } + /** + * Returns the shared element if visible + * @return View if visible, null otherwise + */ + public View getSharedElement() { + if (UIUtils.isViewInBounds(mediaPanel, mediaPoster)) { + return mediaPoster; + } + + return null; + } + /** * Movie details query parameters. */ diff --git a/app/src/main/java/org/xbmc/kore/ui/MoviesActivity.java b/app/src/main/java/org/xbmc/kore/ui/MoviesActivity.java index 792559f..faa6088 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MoviesActivity.java +++ b/app/src/main/java/org/xbmc/kore/ui/MoviesActivity.java @@ -26,12 +26,16 @@ import android.transition.Transition; import android.transition.TransitionInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.view.Window; import org.xbmc.kore.R; import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.Utils; +import java.util.List; +import java.util.Map; + /** * Controls the presentation of Movies information (list, details) * All the information is presented by specific fragments @@ -48,6 +52,8 @@ public class MoviesActivity extends BaseActivity private NavigationDrawerFragment navigationDrawerFragment; + private boolean clearSharedElements; + @TargetApi(21) @Override protected void onCreate(Bundle savedInstanceState) { @@ -76,6 +82,18 @@ public class MoviesActivity extends BaseActivity movieListFragment.setReenterTransition(fade); movieListFragment.setSharedElementReturnTransition(TransitionInflater.from( this).inflateTransition(R.transition.change_image)); + + android.support.v4.app.SharedElementCallback seCallback = new android.support.v4.app.SharedElementCallback() { + @Override + public void onMapSharedElements(List names, Map sharedElements) { + if (clearSharedElements) { + names.clear(); + sharedElements.clear(); + clearSharedElements = false; + } + } + }; + movieListFragment.setExitSharedElementCallback(seCallback); } getSupportFragmentManager() .beginTransaction() @@ -189,9 +207,27 @@ public class MoviesActivity extends BaseActivity // Set up transitions if (Utils.isLollipopOrLater()) { - MovieDetailsFragment movieDetailsFragment = MovieDetailsFragment.newInstance(vh); + final MovieDetailsFragment movieDetailsFragment = MovieDetailsFragment.newInstance(vh); FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction(); + 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 (movieDetailsFragment.isVisible()) { + View sharedView = movieDetailsFragment.getSharedElement(); + if (sharedView == null) { // shared element not visible + clearSharedElements = true; + } + } + } + }; + movieDetailsFragment.setEnterSharedElementCallback(seCallback); + movieDetailsFragment.setEnterTransition(TransitionInflater .from(this) .inflateTransition(R.transition.media_details)); 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 e5306ba..1cc0e46 100644 --- a/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java +++ b/app/src/main/java/org/xbmc/kore/ui/MusicActivity.java @@ -26,11 +26,15 @@ import android.transition.Transition; import android.transition.TransitionInflater; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import org.xbmc.kore.R; import org.xbmc.kore.utils.LogUtils; import org.xbmc.kore.utils.Utils; +import java.util.List; +import java.util.Map; + /** * Controls the presentation of Music information (list, details) * All the information is presented by specific fragments @@ -62,6 +66,8 @@ public class MusicActivity extends BaseActivity private NavigationDrawerFragment navigationDrawerFragment; + private boolean clearSharedElements; + @TargetApi(21) @Override protected void onCreate(Bundle savedInstanceState) { @@ -255,6 +261,18 @@ public class MusicActivity extends BaseActivity FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction(); // Setup animations if (Utils.isLollipopOrLater()) { + android.support.v4.app.SharedElementCallback seCallback = new android.support.v4.app.SharedElementCallback() { + @Override + public void onMapSharedElements(List names, Map sharedElements) { + if (clearSharedElements) { + names.clear(); + sharedElements.clear(); + clearSharedElements = false; + } + } + }; + albumListFragment.setExitSharedElementCallback(seCallback); + //Fade added to prevent shared element from disappearing very shortly at the start of the transition. Transition fade = TransitionInflater .from(this) @@ -281,11 +299,29 @@ public class MusicActivity extends BaseActivity selectedAlbumTitle = vh.albumTitle; // Replace list fragment - AlbumDetailsFragment albumDetailsFragment = AlbumDetailsFragment.newInstance(vh); + final AlbumDetailsFragment albumDetailsFragment = AlbumDetailsFragment.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 (albumDetailsFragment.isVisible()) { + View sharedView = albumDetailsFragment.getSharedElement(); + if (sharedView == null) { // shared element not visible + clearSharedElements = true; + } + } + } + }; + albumDetailsFragment.setEnterSharedElementCallback(seCallback); + albumDetailsFragment.setEnterTransition(TransitionInflater .from(this) .inflateTransition(R.transition.media_details)); diff --git a/app/src/main/java/org/xbmc/kore/utils/UIUtils.java b/app/src/main/java/org/xbmc/kore/utils/UIUtils.java index b28160a..1b6cf0e 100644 --- a/app/src/main/java/org/xbmc/kore/utils/UIUtils.java +++ b/app/src/main/java/org/xbmc/kore/utils/UIUtils.java @@ -122,16 +122,16 @@ public class UIUtils { if ((imageWidth) > 0 && (imageHeight > 0)) { hostManager.getPicasso() - .load(hostManager.getHostInfo().getImageUrl(imageUrl)) - .resize(imageWidth, imageHeight) - .centerCrop() - .into(imageView); + .load(hostManager.getHostInfo().getImageUrl(imageUrl)) + .resize(imageWidth, imageHeight) + .centerCrop() + .into(imageView); } else { hostManager.getPicasso() - .load(hostManager.getHostInfo().getImageUrl(imageUrl)) - .fit() - .centerCrop() - .into(imageView); + .load(hostManager.getHostInfo().getImageUrl(imageUrl)) + .fit() + .centerCrop() + .into(imageView); } } @@ -191,11 +191,11 @@ public class UIUtils { } char charAvatar = TextUtils.isEmpty(str) ? - ' ' : str.charAt(0); + ' ' : str.charAt(0); avatarColorsIdx = TextUtils.isEmpty(str) ? 0 : - Math.max(Character.getNumericValue(str.charAt(0)) + - Character.getNumericValue(str.charAt(str.length() - 1)) + - str.length(), 0) % characterAvatarColors.length(); + Math.max(Character.getNumericValue(str.charAt(0)) + + Character.getNumericValue(str.charAt(str.length() - 1)) + + str.length(), 0) % characterAvatarColors.length(); int color = characterAvatarColors.getColor(avatarColorsIdx, 0xff000000); // avatarColorsIdx = randomGenerator.nextInt(characterAvatarColors.length()); return new CharacterDrawable(charAvatar, color); @@ -318,7 +318,7 @@ public class UIUtils { @Override public void run() { NetUtils.sendWolMagicPacket(hostInfo.getMacAddress(), - hostInfo.getAddress(), hostInfo.getWolPort()); + hostInfo.getAddress(), hostInfo.getWolPort()); } }).start(); Toast.makeText(context, R.string.wol_sent, Toast.LENGTH_SHORT).show(); @@ -423,7 +423,7 @@ public class UIUtils { // Show the animation int endRadius = Math.max(exitTransitionView.getHeight(), exitTransitionView.getWidth()); Animator exitAnim = ViewAnimationUtils.createCircularReveal(exitTransitionView, - centerX, centerY, 0, endRadius); + centerX, centerY, 0, endRadius); exitAnim.setDuration(200); exitAnim.addListener(new Animator.AnimatorListener() {