Switch to use exo controls

This commit is contained in:
Ammar Githam 2021-05-03 03:16:40 +09:00
parent d8f476ea66
commit a6e9a34024
9 changed files with 556 additions and 481 deletions

View File

@ -12,7 +12,6 @@ import awais.instagrabber.adapters.viewholder.SliderPhotoViewHolder;
import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder; import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder;
import awais.instagrabber.customviews.VerticalDragHelper; import awais.instagrabber.customviews.VerticalDragHelper;
import awais.instagrabber.databinding.ItemSliderPhotoBinding; import awais.instagrabber.databinding.ItemSliderPhotoBinding;
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
import awais.instagrabber.models.enums.MediaItemType; import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
@ -22,7 +21,7 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener; private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener;
private final boolean loadVideoOnItemClick; private final boolean loadVideoOnItemClick;
private final SliderCallback sliderCallback; private final SliderCallback sliderCallback;
private final LayoutExoCustomControlsBinding controlsBinding; // private final LayoutExoCustomControlsBinding controlsBinding;
private static final DiffUtil.ItemCallback<Media> DIFF_CALLBACK = new DiffUtil.ItemCallback<Media>() { private static final DiffUtil.ItemCallback<Media> DIFF_CALLBACK = new DiffUtil.ItemCallback<Media>() {
@Override @Override
@ -37,14 +36,14 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
}; };
public SliderItemsAdapter(final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener, public SliderItemsAdapter(final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener,
final LayoutExoCustomControlsBinding controlsBinding, // final LayoutExoCustomControlsBinding controlsBinding,
final boolean loadVideoOnItemClick, final boolean loadVideoOnItemClick,
final SliderCallback sliderCallback) { final SliderCallback sliderCallback) {
super(DIFF_CALLBACK); super(DIFF_CALLBACK);
this.onVerticalDragListener = onVerticalDragListener; this.onVerticalDragListener = onVerticalDragListener;
this.loadVideoOnItemClick = loadVideoOnItemClick; this.loadVideoOnItemClick = loadVideoOnItemClick;
this.sliderCallback = sliderCallback; this.sliderCallback = sliderCallback;
this.controlsBinding = controlsBinding; // this.controlsBinding = controlsBinding;
} }
@NonNull @NonNull
@ -55,7 +54,7 @@ public final class SliderItemsAdapter extends ListAdapter<Media, SliderItemViewH
switch (mediaItemType) { switch (mediaItemType) {
case MEDIA_TYPE_VIDEO: { case MEDIA_TYPE_VIDEO: {
final LayoutVideoPlayerWithThumbnailBinding binding = LayoutVideoPlayerWithThumbnailBinding.inflate(inflater, parent, false); final LayoutVideoPlayerWithThumbnailBinding binding = LayoutVideoPlayerWithThumbnailBinding.inflate(inflater, parent, false);
return new SliderVideoViewHolder(binding, onVerticalDragListener, controlsBinding, loadVideoOnItemClick); return new SliderVideoViewHolder(binding, onVerticalDragListener, loadVideoOnItemClick);
} }
case MEDIA_TYPE_IMAGE: case MEDIA_TYPE_IMAGE:
default: default:

View File

@ -13,7 +13,6 @@ import awais.instagrabber.adapters.SliderItemsAdapter;
import awais.instagrabber.customviews.VerticalDragHelper; import awais.instagrabber.customviews.VerticalDragHelper;
import awais.instagrabber.customviews.VideoPlayerCallbackAdapter; import awais.instagrabber.customviews.VideoPlayerCallbackAdapter;
import awais.instagrabber.customviews.VideoPlayerViewHelper; import awais.instagrabber.customviews.VideoPlayerViewHelper;
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
import awais.instagrabber.repositories.responses.Media; import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.VideoVersion; import awais.instagrabber.repositories.responses.VideoVersion;
@ -28,7 +27,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
private static final String TAG = "SliderVideoViewHolder"; private static final String TAG = "SliderVideoViewHolder";
private final LayoutVideoPlayerWithThumbnailBinding binding; private final LayoutVideoPlayerWithThumbnailBinding binding;
private final LayoutExoCustomControlsBinding controlsBinding; // private final LayoutExoCustomControlsBinding controlsBinding;
private final boolean loadVideoOnItemClick; private final boolean loadVideoOnItemClick;
private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() { private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override @Override
@ -43,11 +42,11 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
public SliderVideoViewHolder(@NonNull final LayoutVideoPlayerWithThumbnailBinding binding, public SliderVideoViewHolder(@NonNull final LayoutVideoPlayerWithThumbnailBinding binding,
final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener, final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener,
final LayoutExoCustomControlsBinding controlsBinding, // final LayoutExoCustomControlsBinding controlsBinding,
final boolean loadVideoOnItemClick) { final boolean loadVideoOnItemClick) {
super(binding.getRoot()); super(binding.getRoot());
this.binding = binding; this.binding = binding;
this.controlsBinding = controlsBinding; // this.controlsBinding = controlsBinding;
this.loadVideoOnItemClick = loadVideoOnItemClick; this.loadVideoOnItemClick = loadVideoOnItemClick;
// if (onVerticalDragListener != null) { // if (onVerticalDragListener != null) {
// final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent); // final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent);
@ -139,7 +138,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
aspectRatio, aspectRatio,
ResponseBodyUtils.getThumbUrl(media), ResponseBodyUtils.getThumbUrl(media),
loadVideoOnItemClick, loadVideoOnItemClick,
controlsBinding, // controlsBinding,
videoPlayerCallback); videoPlayerCallback);
// binding.itemFeedBottom.btnMute.setOnClickListener(v -> { // binding.itemFeedBottom.btnMute.setOnClickListener(v -> {
// final float newVol = videoPlayerViewHelper.toggleMute(); // final float newVol = videoPlayerViewHelper.toggleMute();
@ -163,15 +162,15 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
videoPlayerViewHelper.releasePlayer(); videoPlayerViewHelper.releasePlayer();
} }
public void resetPlayerTimeline() { // public void resetPlayerTimeline() {
if (videoPlayerViewHelper == null) return; // if (videoPlayerViewHelper == null) return;
videoPlayerViewHelper.resetTimeline(); // videoPlayerViewHelper.resetTimeline();
} // }
//
public void removeCallbacks() { // public void removeCallbacks() {
if (videoPlayerViewHelper == null) return; // if (videoPlayerViewHelper == null) return;
videoPlayerViewHelper.removeCallbacks(); // videoPlayerViewHelper.removeCallbacks();
} // }
// private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) { // private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) {
// final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams(); // final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams();

View File

@ -45,7 +45,7 @@ public class FeedSliderViewHolder extends FeedItemViewHolder {
final String text = "1/" + sliderItemLen; final String text = "1/" + sliderItemLen;
binding.mediaCounter.setText(text); binding.mediaCounter.setText(text);
binding.mediaList.setOffscreenPageLimit(1); binding.mediaList.setOffscreenPageLimit(1);
final SliderItemsAdapter adapter = new SliderItemsAdapter(null, null, false, new SliderCallbackAdapter() { final SliderItemsAdapter adapter = new SliderItemsAdapter(null, false, new SliderCallbackAdapter() {
@Override @Override
public void onItemClicked(final int position) { public void onItemClicked(final int position) {
feedItemCallback.onSliderClick(feedModel, position); feedItemCallback.onSliderClick(feedModel, position);

View File

@ -97,7 +97,7 @@ public class FeedVideoViewHolder extends FeedItemViewHolder {
aspectRatio, aspectRatio,
ResponseBodyUtils.getThumbUrl(media), ResponseBodyUtils.getThumbUrl(media),
false, false,
null, // null,
videoPlayerCallback); videoPlayerCallback);
binding.videoPost.thumbnail.post(() -> { binding.videoPost.thumbnail.post(() -> {
if (media.getOriginalHeight() > 0.8 * Utils.displayMetrics.heightPixels) { if (media.getOriginalHeight() > 0.8 * Utils.displayMetrics.heightPixels) {

View File

@ -3,14 +3,11 @@ package awais.instagrabber.customviews;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.net.Uri; import android.net.Uri;
import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.PopupMenu;
import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.Fresco;
@ -21,103 +18,95 @@ import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioListener; import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.source.ProgressiveMediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.material.slider.LabelFormatter; import com.google.android.material.button.MaterialButton;
import com.google.android.material.slider.Slider;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding;
import awais.instagrabber.utils.TextUtils;
import static com.google.android.exoplayer2.C.TIME_UNSET;
import static com.google.android.exoplayer2.Player.STATE_ENDED;
import static com.google.android.exoplayer2.Player.STATE_IDLE;
import static com.google.android.exoplayer2.Player.STATE_READY;
public class VideoPlayerViewHelper implements Player.EventListener { public class VideoPlayerViewHelper implements Player.EventListener {
private static final String TAG = "VideoPlayerViewHelper"; private static final String TAG = "VideoPlayerViewHelper";
private static final long INITIAL_DELAY = 0; // private static final long INITIAL_DELAY = 0;
private static final long RECURRING_DELAY = 60; // private static final long RECURRING_DELAY = 60;
private final Context context; private final Context context;
private final awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding binding; private final LayoutVideoPlayerWithThumbnailBinding binding;
private final float initialVolume; private final float initialVolume;
private final float thumbnailAspectRatio; private final float thumbnailAspectRatio;
private final String thumbnailUrl; private final String thumbnailUrl;
private final boolean loadPlayerOnClick; private final boolean loadPlayerOnClick;
private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding; // private final LayoutExoCustomControlsBinding controlsBinding;
private final VideoPlayerCallback videoPlayerCallback; private final VideoPlayerCallback videoPlayerCallback;
private final String videoUrl; private final String videoUrl;
private final DefaultDataSourceFactory dataSourceFactory; private final DefaultDataSourceFactory dataSourceFactory;
private SimpleExoPlayer player; private SimpleExoPlayer player;
private PopupMenu speedPopup; private PopupMenu speedPopup;
private PositionCheckRunnable positionChecker; // private PositionCheckRunnable positionChecker;
private Handler positionUpdateHandler; // private Handler positionUpdateHandler;
private final Player.EventListener listener = new Player.EventListener() { // private final Player.EventListener listener = new Player.EventListener() {
@Override // @Override
public void onPlaybackStateChanged(final int state) { // public void onPlaybackStateChanged(final int state) {
switch (state) { // // switch (state) {
case Player.STATE_BUFFERING: // // case Player.STATE_BUFFERING:
case STATE_IDLE: // // case STATE_IDLE:
case STATE_ENDED: // // case STATE_ENDED:
positionUpdateHandler.removeCallbacks(positionChecker); // // positionUpdateHandler.removeCallbacks(positionChecker);
return; // // return;
case STATE_READY: // // case STATE_READY:
setupTimeline(); // // setupTimeline();
positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); // // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY);
break; // // break;
} // // }
} // }
//
@Override // @Override
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { // public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
updatePlayPauseDrawable(playWhenReady); // // updatePlayPauseDrawable(playWhenReady);
if (positionUpdateHandler == null || positionChecker == null) return; // // if (positionUpdateHandler == null || positionChecker == null) return;
if (playWhenReady) { // // if (playWhenReady) {
positionUpdateHandler.removeCallbacks(positionChecker); // // positionUpdateHandler.removeCallbacks(positionChecker);
positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); // // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY);
} // // }
} // }
}; // };
private final AudioListener audioListener = new AudioListener() { private final AudioListener audioListener = new AudioListener() {
@Override @Override
public void onVolumeChanged(final float volume) { public void onVolumeChanged(final float volume) {
updateMuteIcon(volume); updateMuteIcon(volume);
} }
}; };
private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> { // private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> {
if (!fromUser) return; // if (!fromUser) return;
long actualValue = (long) value; // long actualValue = (long) value;
if (actualValue < 0) { // if (actualValue < 0) {
actualValue = 0; // actualValue = 0;
} else if (actualValue > player.getDuration()) { // } else if (actualValue > player.getDuration()) {
actualValue = player.getDuration(); // actualValue = player.getDuration();
} // }
player.seekTo(actualValue); // player.seekTo(actualValue);
}; // };
private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady()); // private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady());
private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value); // // private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value);
private final View.OnClickListener muteOnClickListener = v -> toggleMute(); private final View.OnClickListener muteOnClickListener = v -> toggleMute();
private final View.OnClickListener rewOnClickListener = v -> { private MaterialButton mute;
final long positionMs = player.getCurrentPosition() - 5000; // private final View.OnClickListener rewOnClickListener = v -> {
player.seekTo(positionMs < 0 ? 0 : positionMs); // final long positionMs = player.getCurrentPosition() - 5000;
}; // player.seekTo(positionMs < 0 ? 0 : positionMs);
private final View.OnClickListener ffOnClickListener = v -> { // };
long positionMs = player.getCurrentPosition() + 5000; // private final View.OnClickListener ffOnClickListener = v -> {
long duration = player.getDuration(); // long positionMs = player.getCurrentPosition() + 5000;
if (duration == TIME_UNSET) { // long duration = player.getDuration();
duration = 0; // if (duration == TIME_UNSET) {
} // duration = 0;
player.seekTo(Math.min(positionMs, duration)); // }
}; // player.seekTo(Math.min(positionMs, duration));
private final View.OnClickListener showMenu = this::showMenu; // };
// private final View.OnClickListener showMenu = this::showMenu;
public VideoPlayerViewHelper(@NonNull final Context context, public VideoPlayerViewHelper(@NonNull final Context context,
@NonNull final LayoutVideoPlayerWithThumbnailBinding binding, @NonNull final LayoutVideoPlayerWithThumbnailBinding binding,
@ -126,7 +115,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
final float thumbnailAspectRatio, final float thumbnailAspectRatio,
final String thumbnailUrl, final String thumbnailUrl,
final boolean loadPlayerOnClick, final boolean loadPlayerOnClick,
final LayoutExoCustomControlsBinding controlsBinding, // final LayoutExoCustomControlsBinding controlsBinding,
final VideoPlayerCallback videoPlayerCallback) { final VideoPlayerCallback videoPlayerCallback) {
this.context = context; this.context = context;
this.binding = binding; this.binding = binding;
@ -134,7 +123,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
this.thumbnailAspectRatio = thumbnailAspectRatio; this.thumbnailAspectRatio = thumbnailAspectRatio;
this.thumbnailUrl = thumbnailUrl; this.thumbnailUrl = thumbnailUrl;
this.loadPlayerOnClick = loadPlayerOnClick; this.loadPlayerOnClick = loadPlayerOnClick;
this.controlsBinding = controlsBinding; // this.controlsBinding = controlsBinding;
this.videoPlayerCallback = videoPlayerCallback; this.videoPlayerCallback = videoPlayerCallback;
this.videoUrl = videoUrl; this.videoUrl = videoUrl;
this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram"); this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram");
@ -151,7 +140,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
} }
}); });
setThumbnail(); setThumbnail();
setupControls(); // setupControls();
} }
private void setThumbnail() { private void setThumbnail() {
@ -200,12 +189,13 @@ public class VideoPlayerViewHelper implements Player.EventListener {
player = new SimpleExoPlayer.Builder(context) player = new SimpleExoPlayer.Builder(context)
.setLooper(Looper.getMainLooper()) .setLooper(Looper.getMainLooper())
.build(); .build();
positionUpdateHandler = new Handler(); // positionUpdateHandler = new Handler();
positionChecker = new PositionCheckRunnable(positionUpdateHandler, // positionChecker = new PositionCheckRunnable(positionUpdateHandler,
player, // player,
controlsBinding.timeline, // controlsBinding.timeline,
controlsBinding.fromTime); // controlsBinding.fromTime);
player.addListener(this); player.addListener(this);
player.addAudioListener(audioListener);
player.setVolume(initialVolume); player.setVolume(initialVolume);
player.setPlayWhenReady(true); player.setPlayWhenReady(true);
player.setRepeatMode(Player.REPEAT_MODE_ALL); player.setRepeatMode(Player.REPEAT_MODE_ALL);
@ -213,124 +203,134 @@ public class VideoPlayerViewHelper implements Player.EventListener {
final MediaItem mediaItem = MediaItem.fromUri(videoUrl); final MediaItem mediaItem = MediaItem.fromUri(videoUrl);
final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem); final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem);
player.setMediaSource(mediaSource); player.setMediaSource(mediaSource);
setupControls(); // setupControls();
player.prepare(); player.prepare();
binding.playerView.setPlayer(player); binding.playerView.setPlayer(player);
} binding.playerView.setShowFastForwardButton(false);
binding.playerView.setShowRewindButton(false);
private void setupControls() { // binding.controls.setPlayer(player);
if (controlsBinding == null) return; mute = binding.playerView.findViewById(R.id.mute);
binding.playerView.setUseController(false); // mute = binding.controls.findViewById(R.id.mute);
if (player == null) { if (mute != null) {
enableControls(false); mute.setOnClickListener(muteOnClickListener);
// controlsBinding.playPause.setEnabled(true);
// controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent));
return;
} }
enableControls(true);
updatePlayPauseDrawable(player.getPlayWhenReady());
updateMuteIcon(player.getVolume()); updateMuteIcon(player.getVolume());
player.addListener(listener);
player.addAudioListener(audioListener);
controlsBinding.timeline.addOnChangeListener(onChangeListener);
controlsBinding.timeline.setLabelFormatter(labelFormatter);
controlsBinding.playPause.setOnClickListener(onClickListener);
controlsBinding.mute.setOnClickListener(muteOnClickListener);
controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener);
controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener);
controlsBinding.speed.setOnClickListener(showMenu);
} }
private void setupTimeline() { // private void setupControls() {
final long duration = player.getDuration(); // if (controlsBinding == null) return;
controlsBinding.timeline.setEnabled(true); // // binding.playerView.setUseController(false);
controlsBinding.timeline.setValueFrom(0); // if (player == null) {
controlsBinding.timeline.setValueTo(duration); // // enableControls(false);
controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0)); // // controlsBinding.playPause.setEnabled(true);
controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration)); // // controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent));
} // return;
// }
// // enableControls(true);
// // updatePlayPauseDrawable(player.getPlayWhenReady());
// // updateMuteIcon(player.getVolume());
// player.addListener(listener);
// // player.addAudioListener(audioListener);
// // controlsBinding.timeline.addOnChangeListener(onChangeListener);
// // controlsBinding.timeline.setLabelFormatter(labelFormatter);
// // controlsBinding.playPause.setOnClickListener(onClickListener);
// // controlsBinding.mute.setOnClickListener(muteOnClickListener);
// // controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener);
// // controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener);
// // controlsBinding.speed.setOnClickListener(showMenu);
// }
private void enableControls(final boolean enable) { // private void setupTimeline() {
controlsBinding.speed.setEnabled(enable); // final long duration = player.getDuration();
controlsBinding.speed.setClickable(enable); // controlsBinding.timeline.setEnabled(true);
controlsBinding.mute.setEnabled(enable); // controlsBinding.timeline.setValueFrom(0);
controlsBinding.mute.setClickable(enable); // controlsBinding.timeline.setValueTo(duration);
controlsBinding.ffWithAmount.setEnabled(enable); // controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0));
controlsBinding.ffWithAmount.setClickable(enable); // controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration));
controlsBinding.rewWithAmount.setEnabled(enable); // }
controlsBinding.rewWithAmount.setClickable(enable);
controlsBinding.fromTime.setEnabled(enable);
controlsBinding.toTime.setEnabled(enable);
controlsBinding.playPause.setEnabled(enable);
controlsBinding.playPause.setClickable(enable);
controlsBinding.timeline.setEnabled(enable);
}
public void showMenu(View anchor) { // private void enableControls(final boolean enable) {
PopupMenu popup = getPopupMenu(anchor); // controlsBinding.speed.setEnabled(enable);
popup.show(); // controlsBinding.speed.setClickable(enable);
} // controlsBinding.mute.setEnabled(enable);
// controlsBinding.mute.setClickable(enable);
// controlsBinding.ffWithAmount.setEnabled(enable);
// controlsBinding.ffWithAmount.setClickable(enable);
// controlsBinding.rewWithAmount.setEnabled(enable);
// controlsBinding.rewWithAmount.setClickable(enable);
// // controlsBinding.fromTime.setEnabled(enable);
// // controlsBinding.toTime.setEnabled(enable);
// controlsBinding.playPause.setEnabled(enable);
// controlsBinding.playPause.setClickable(enable);
// // controlsBinding.timeline.setEnabled(enable);
// }
@NonNull // public void showMenu(View anchor) {
private PopupMenu getPopupMenu(final View anchor) { // PopupMenu popup = getPopupMenu(anchor);
if (speedPopup != null) { // popup.show();
return speedPopup; // }
}
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle); // @NonNull
// final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer); // private PopupMenu getPopupMenu(final View anchor) {
speedPopup = new PopupMenu(themeWrapper, anchor); // if (speedPopup != null) {
speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu()); // return speedPopup;
speedPopup.setOnMenuItemClickListener(item -> { // }
float nextSpeed; // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
int textResId; // // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer);
int itemId = item.getItemId(); // speedPopup = new PopupMenu(themeWrapper, anchor);
if (itemId == R.id.pt_two_five_x) { // speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu());
nextSpeed = 0.25f; // speedPopup.setOnMenuItemClickListener(item -> {
textResId = R.string.pt_two_five_x; // float nextSpeed;
} else if (itemId == R.id.pt_five_x) { // int textResId;
nextSpeed = 0.5f; // int itemId = item.getItemId();
textResId = R.string.pt_five_x; // if (itemId == R.id.pt_two_five_x) {
} else if (itemId == R.id.pt_seven_five_x) { // nextSpeed = 0.25f;
nextSpeed = 0.75f; // textResId = R.string.pt_two_five_x;
textResId = R.string.pt_seven_five_x; // } else if (itemId == R.id.pt_five_x) {
} else if (itemId == R.id.one_x) { // nextSpeed = 0.5f;
nextSpeed = 1f; // textResId = R.string.pt_five_x;
textResId = R.string.one_x; // } else if (itemId == R.id.pt_seven_five_x) {
} else if (itemId == R.id.one_pt_two_five_x) { // nextSpeed = 0.75f;
nextSpeed = 1.25f; // textResId = R.string.pt_seven_five_x;
textResId = R.string.one_pt_two_five_x; // } else if (itemId == R.id.one_x) {
} else if (itemId == R.id.one_pt_five_x) { // nextSpeed = 1f;
nextSpeed = 1.5f; // textResId = R.string.one_x;
textResId = R.string.one_pt_five_x; // } else if (itemId == R.id.one_pt_two_five_x) {
} else if (itemId == R.id.two_x) { // nextSpeed = 1.25f;
nextSpeed = 2f; // textResId = R.string.one_pt_two_five_x;
textResId = R.string.two_x; // } else if (itemId == R.id.one_pt_five_x) {
} else { // nextSpeed = 1.5f;
nextSpeed = 1; // textResId = R.string.one_pt_five_x;
textResId = R.string.one_x; // } else if (itemId == R.id.two_x) {
} // nextSpeed = 2f;
player.setPlaybackParameters(new PlaybackParameters(nextSpeed)); // textResId = R.string.two_x;
controlsBinding.speed.setText(textResId); // } else {
return true; // nextSpeed = 1;
}); // textResId = R.string.one_x;
return speedPopup; // }
} // player.setPlaybackParameters(new PlaybackParameters(nextSpeed));
// controlsBinding.speed.setText(textResId);
// return true;
// });
// return speedPopup;
// }
private void updateMuteIcon(final float volume) { private void updateMuteIcon(final float volume) {
if (mute == null) return;
if (volume == 0) { if (volume == 0) {
controlsBinding.mute.setIconResource(R.drawable.ic_volume_off_24_states); mute.setIconResource(R.drawable.ic_volume_off_24_states);
return; return;
} }
controlsBinding.mute.setIconResource(R.drawable.ic_volume_up_24_states); mute.setIconResource(R.drawable.ic_volume_up_24_states);
} }
private void updatePlayPauseDrawable(final boolean playWhenReady) { // private void updatePlayPauseDrawable(final boolean playWhenReady) {
if (playWhenReady) { // if (playWhenReady) {
controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24); // controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24);
return; // return;
} // }
controlsBinding.playPause.setIconResource(R.drawable.ic_play_states); // controlsBinding.playPause.setIconResource(R.drawable.ic_play_states);
} // }
@Override @Override
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
@ -343,15 +343,14 @@ public class VideoPlayerViewHelper implements Player.EventListener {
} }
@Override @Override
public void onPlayerError(final ExoPlaybackException error) { public void onPlayerError(@NonNull final ExoPlaybackException error) {
Log.e(TAG, "onPlayerError", error); Log.e(TAG, "onPlayerError", error);
} }
public float toggleMute() { private void toggleMute() {
if (player == null) return 0; if (player == null) return;
final float vol = player.getVolume() == 0f ? 1f : 0f; final float vol = player.getVolume() == 0f ? 1f : 0f;
player.setVolume(vol); player.setVolume(vol);
return vol;
} }
// public void togglePlayback() { // public void togglePlayback() {
@ -370,85 +369,85 @@ public class VideoPlayerViewHelper implements Player.EventListener {
player.release(); player.release();
player = null; player = null;
} }
if (positionUpdateHandler != null) { // if (positionUpdateHandler != null) {
if (positionChecker != null) { // if (positionChecker != null) {
positionUpdateHandler.removeCallbacks(positionChecker); // positionUpdateHandler.removeCallbacks(positionChecker);
positionChecker = null; // positionChecker = null;
} // }
positionUpdateHandler = null; // positionUpdateHandler = null;
} // }
} }
public void pause() { public void pause() {
if (player != null) { if (player != null) {
player.pause(); player.pause();
} }
if (positionUpdateHandler != null) { // if (positionUpdateHandler != null) {
if (positionChecker != null) { // if (positionChecker != null) {
positionUpdateHandler.removeCallbacks(positionChecker); // positionUpdateHandler.removeCallbacks(positionChecker);
} // }
} // }
} }
public void resetTimeline() { // public void resetTimeline() {
if (player == null) { // if (player == null) {
enableControls(false); // enableControls(false);
return; // return;
} // }
setupTimeline(); // setupTimeline();
final long currentPosition = player.getCurrentPosition(); // final long currentPosition = player.getCurrentPosition();
controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration())); // controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration()));
setupControls(); // setupControls();
} // }
public void removeCallbacks() { // public void removeCallbacks() {
if (player != null) { // if (player != null) {
player.removeListener(listener); // player.removeListener(listener);
player.removeAudioListener(audioListener); // player.removeAudioListener(audioListener);
} // }
controlsBinding.timeline.removeOnChangeListener(onChangeListener); // controlsBinding.timeline.removeOnChangeListener(onChangeListener);
controlsBinding.timeline.setLabelFormatter(null); // controlsBinding.timeline.setLabelFormatter(null);
controlsBinding.playPause.setOnClickListener(null); // controlsBinding.playPause.setOnClickListener(null);
controlsBinding.mute.setOnClickListener(null); // controlsBinding.mute.setOnClickListener(null);
controlsBinding.rewWithAmount.setOnClickListener(null); // controlsBinding.rewWithAmount.setOnClickListener(null);
controlsBinding.ffWithAmount.setOnClickListener(null); // controlsBinding.ffWithAmount.setOnClickListener(null);
controlsBinding.speed.setOnClickListener(null); // controlsBinding.speed.setOnClickListener(null);
} // }
private static class PositionCheckRunnable implements Runnable { // private static class PositionCheckRunnable implements Runnable {
private final Handler positionUpdateHandler; // private final Handler positionUpdateHandler;
private final SimpleExoPlayer player; // private final SimpleExoPlayer player;
private final Slider timeline; // private final Slider timeline;
private final AppCompatTextView fromTime; // private final AppCompatTextView fromTime;
//
public PositionCheckRunnable(final Handler positionUpdateHandler, // public PositionCheckRunnable(final Handler positionUpdateHandler,
final SimpleExoPlayer simpleExoPlayer, // final SimpleExoPlayer simpleExoPlayer,
final Slider slider, // final Slider slider,
final AppCompatTextView fromTime) { // final AppCompatTextView fromTime) {
this.positionUpdateHandler = positionUpdateHandler; // this.positionUpdateHandler = positionUpdateHandler;
this.player = simpleExoPlayer; // this.player = simpleExoPlayer;
this.timeline = slider; // this.timeline = slider;
this.fromTime = fromTime; // this.fromTime = fromTime;
} // }
//
@Override // @Override
public void run() { // public void run() {
if (positionUpdateHandler == null) return; // if (positionUpdateHandler == null) return;
positionUpdateHandler.removeCallbacks(this); // positionUpdateHandler.removeCallbacks(this);
if (player == null) return; // if (player == null) return;
final long currentPosition = player.getCurrentPosition(); // final long currentPosition = player.getCurrentPosition();
final long duration = player.getDuration(); // final long duration = player.getDuration();
if (duration == TIME_UNSET) { // if (duration == TIME_UNSET) {
timeline.setValueFrom(0); // timeline.setValueFrom(0);
timeline.setValueTo(0); // timeline.setValueTo(0);
timeline.setEnabled(false); // timeline.setEnabled(false);
return; // return;
} // }
timeline.setValue(Math.min(currentPosition, duration)); // timeline.setValue(Math.min(currentPosition, duration));
fromTime.setText(TextUtils.millisToTimeString(currentPosition)); // fromTime.setText(TextUtils.millisToTimeString(currentPosition));
positionUpdateHandler.postDelayed(this, RECURRING_DELAY); // positionUpdateHandler.postDelayed(this, RECURRING_DELAY);
} // }
} // }
public interface VideoPlayerCallback { public interface VideoPlayerCallback {
void onThumbnailLoaded(); void onThumbnailLoaded();

View File

@ -27,7 +27,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.view.Window; import android.view.Window;
@ -44,7 +43,6 @@ import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.PopupMenu;
import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.PermissionChecker; import androidx.core.content.PermissionChecker;
import androidx.core.view.ViewCompat;
import androidx.core.widget.NestedScrollView; import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
@ -119,10 +117,11 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
// private MediaService mediaService; // private MediaService mediaService;
private Context context; private Context context;
private BottomSheetBehavior<NestedScrollView> bottomSheetBehavior; private BottomSheetBehavior<NestedScrollView> bottomSheetBehavior;
private boolean detailsVisible = true, video; private boolean detailsVisible = true;
private boolean video;
private VideoPlayerViewHelper videoPlayerViewHelper; private VideoPlayerViewHelper videoPlayerViewHelper;
private SliderItemsAdapter sliderItemsAdapter; private SliderItemsAdapter sliderItemsAdapter;
private boolean wasControlsVisible; // private boolean wasControlsVisible;
private boolean wasPaused; private boolean wasPaused;
private int captionState = BottomSheetBehavior.STATE_HIDDEN; private int captionState = BottomSheetBehavior.STATE_HIDDEN;
private int sliderPosition = -1; private int sliderPosition = -1;
@ -883,9 +882,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
switch (bottomSheetBehavior.getState()) { switch (bottomSheetBehavior.getState()) {
case BottomSheetBehavior.STATE_HIDDEN: case BottomSheetBehavior.STATE_HIDDEN:
binding.captionParent.fullScroll(ScrollView.FOCUS_UP); // reset scroll position binding.captionParent.fullScroll(ScrollView.FOCUS_UP); // reset scroll position
if (binding.playerControls.getRoot().getVisibility() == View.VISIBLE) { // if (binding.playerControls.getRoot().getVisibility() == View.VISIBLE) {
hidePlayerControls(); // hidePlayerControls();
} // }
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
return; return;
case BottomSheetBehavior.STATE_COLLAPSED: case BottomSheetBehavior.STATE_COLLAPSED:
@ -993,8 +992,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
private void setupPostImage() { private void setupPostImage() {
binding.videoPost.root.setVisibility(View.GONE); binding.videoPost.root.setVisibility(View.GONE);
binding.sliderParent.setVisibility(View.GONE); binding.sliderParent.setVisibility(View.GONE);
binding.playerControlsToggle.setVisibility(View.GONE); // binding.playerControlsToggle.setVisibility(View.GONE);
binding.playerControls.getRoot().setVisibility(View.GONE); // binding.playerControls.getRoot().setVisibility(View.GONE);
binding.mediaCounter.setVisibility(View.GONE); binding.mediaCounter.setVisibility(View.GONE);
binding.postImage.setVisibility(View.VISIBLE); binding.postImage.setVisibility(View.VISIBLE);
if (!wasPaused && sharedMainPostElement != null) { if (!wasPaused && sharedMainPostElement != null) {
@ -1049,8 +1048,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
final Media media = viewModel.getMedia(); final Media media = viewModel.getMedia();
binding.postImage.setVisibility(View.GONE); binding.postImage.setVisibility(View.GONE);
binding.videoPost.root.setVisibility(View.GONE); binding.videoPost.root.setVisibility(View.GONE);
binding.playerControlsToggle.setVisibility(View.GONE); // binding.playerControlsToggle.setVisibility(View.GONE);
binding.playerControls.getRoot().setVisibility(View.GONE); // binding.playerControls.getRoot().setVisibility(View.GONE);
binding.sliderParent.setVisibility(View.VISIBLE); binding.sliderParent.setVisibility(View.VISIBLE);
binding.mediaCounter.setVisibility(View.VISIBLE); binding.mediaCounter.setVisibility(View.VISIBLE);
if (!wasPaused && sharedMainPostElement != null) { if (!wasPaused && sharedMainPostElement != null) {
@ -1070,7 +1069,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
}); });
} }
} }
sliderItemsAdapter = new SliderItemsAdapter(null, binding.playerControls, true, new SliderCallbackAdapter() { sliderItemsAdapter = new SliderItemsAdapter(null, true, new SliderCallbackAdapter() {
@Override @Override
public void onThumbnailLoaded(final int position) { public void onThumbnailLoaded(final int position) {
if (position != 0) return; if (position != 0) return;
@ -1087,8 +1086,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
if (activity == null) return; if (activity == null) return;
Utils.enabledKeepScreenOn(activity); Utils.enabledKeepScreenOn(activity);
if (!detailsVisible || hasBeenToggled) return; // if (!detailsVisible || hasBeenToggled) return;
showPlayerControls(); // showPlayerControls();
} }
@Override @Override
@ -1137,27 +1136,29 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
binding.mediaCounter.setText(text); binding.mediaCounter.setText(text);
final Media childMedia = media.getCarouselMedia().get(position); final Media childMedia = media.getCarouselMedia().get(position);
final View view = binding.sliderParent.getChildAt(0); final View view = binding.sliderParent.getChildAt(0);
if (prevPosition != -1) { // if (prevPosition != -1) {
if (view instanceof RecyclerView) { // if (view instanceof RecyclerView) {
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(prevPosition); // final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(prevPosition);
if (viewHolder instanceof SliderVideoViewHolder) { // if (viewHolder instanceof SliderVideoViewHolder) {
((SliderVideoViewHolder) viewHolder).removeCallbacks(); // ((SliderVideoViewHolder) viewHolder).removeCallbacks();
} // }
} // }
} // }
video = false;
if (childMedia.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO) { if (childMedia.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO) {
if (view instanceof RecyclerView) { // if (view instanceof RecyclerView) {
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(position); // final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(position);
if (viewHolder instanceof SliderVideoViewHolder) { // if (viewHolder instanceof SliderVideoViewHolder) {
((SliderVideoViewHolder) viewHolder).resetPlayerTimeline(); // ((SliderVideoViewHolder) viewHolder).resetPlayerTimeline();
} // }
} // }
enablePlayerControls(true); // enablePlayerControls(true);
video = true;
viewModel.setViewCount(childMedia.getViewCount()); viewModel.setViewCount(childMedia.getViewCount());
return; return;
} }
viewModel.setViewCount(null); viewModel.setViewCount(null);
enablePlayerControls(false); // enablePlayerControls(false);
} }
private void pausePlayerAtPosition(final int position, final RecyclerView view) { private void pausePlayerAtPosition(final int position, final RecyclerView view) {
@ -1196,6 +1197,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private void setupVideo() { private void setupVideo() {
video = true;
final Media media = viewModel.getMedia(); final Media media = viewModel.getMedia();
binding.postImage.setVisibility(View.GONE); binding.postImage.setVisibility(View.GONE);
binding.sliderParent.setVisibility(View.GONE); binding.sliderParent.setVisibility(View.GONE);
@ -1211,7 +1213,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
// final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.videoPost.playerView); // final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.videoPost.playerView);
// thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); // thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
// playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); // playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
enablePlayerControls(true); // enablePlayerControls(true);
// binding.videoPost.thumbnailParent.setOnTouchListener((v, event) -> { // binding.videoPost.thumbnailParent.setOnTouchListener((v, event) -> {
// final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event); // final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event);
// if (onDragTouch) { // if (onDragTouch) {
@ -1293,96 +1295,96 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
aspectRatio, aspectRatio,
ResponseBodyUtils.getThumbUrl(media), ResponseBodyUtils.getThumbUrl(media),
true, true,
binding.playerControls, // /*binding.playerControls*/null,
videoPlayerCallback); videoPlayerCallback);
} }
} }
private void enablePlayerControls(final boolean enable) { // private void enablePlayerControls(final boolean enable) {
video = enable; // video = enable;
if (enable) { // if (enable) {
binding.playerControlsToggle.setVisibility(View.VISIBLE); // binding.playerControlsToggle.setVisibility(View.VISIBLE);
binding.playerControlsToggle.setOnClickListener(v -> { // binding.playerControlsToggle.setOnClickListener(v -> {
final int visibility = binding.playerControls.getRoot().getVisibility(); // final int visibility = binding.playerControls.getRoot().getVisibility();
if (visibility == View.GONE) { // if (visibility == View.GONE) {
showPlayerControls(); // showPlayerControls();
return; // return;
} // }
hidePlayerControls(); // hidePlayerControls();
}); // });
return; // return;
} // }
binding.playerControlsToggle.setVisibility(View.GONE); // binding.playerControlsToggle.setVisibility(View.GONE);
hidePlayerControls(); // hidePlayerControls();
} // }
private void hideCaption() { private void hideCaption() {
if (bottomSheetBehavior == null) return; if (bottomSheetBehavior == null) return;
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
} }
private void showPlayerControls() { // private void showPlayerControls() {
hideCaption(); // hideCaption();
// previously invisible view // // previously invisible view
View view = binding.playerControls.getRoot(); // View view = binding.playerControls.getRoot();
if (view.getVisibility() == View.VISIBLE) { // if (view.getVisibility() == View.VISIBLE) {
return; // return;
} // }
if (!ViewCompat.isAttachedToWindow(view)) { // if (!ViewCompat.isAttachedToWindow(view)) {
view.setVisibility(View.VISIBLE); // view.setVisibility(View.VISIBLE);
return; // return;
} // }
// get the center for the clipping circle // // get the center for the clipping circle
int cx = view.getWidth() / 2; // int cx = view.getWidth() / 2;
// int cy = view.getHeight() / 2; // // int cy = view.getHeight() / 2;
int cy = view.getHeight(); // int cy = view.getHeight();
//
// // get the final radius for the clipping circle
// float finalRadius = (float) Math.hypot(cx, cy);
//
// // create the animator for this view (the start radius is zero)
// Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0f, finalRadius);
//
// // make the view visible and start the animation
// view.setVisibility(View.VISIBLE);
// anim.start();
//
// }
// get the final radius for the clipping circle // private void hidePlayerControls() {
float finalRadius = (float) Math.hypot(cx, cy); // // previously visible view
// final View view = binding.playerControls.getRoot();
// create the animator for this view (the start radius is zero) // if (view.getVisibility() == View.GONE) {
Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0f, finalRadius); // return;
// }
// make the view visible and start the animation // if (!ViewCompat.isAttachedToWindow(view)) {
view.setVisibility(View.VISIBLE); // view.setVisibility(View.GONE);
anim.start(); // return;
// }
} //
// // get the center for the clipping circle
private void hidePlayerControls() { // int cx = view.getWidth() / 2;
// previously visible view // // int cy = view.getHeight() / 2;
final View view = binding.playerControls.getRoot(); // int cy = view.getHeight();
if (view.getVisibility() == View.GONE) { //
return; // // get the initial radius for the clipping circle
} // float initialRadius = (float) Math.hypot(cx, cy);
if (!ViewCompat.isAttachedToWindow(view)) { //
view.setVisibility(View.GONE); // // create the animation (the final radius is zero)
return; // Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0f);
} //
// // make the view invisible when the animation is done
// get the center for the clipping circle // anim.addListener(new AnimatorListenerAdapter() {
int cx = view.getWidth() / 2; // @Override
// int cy = view.getHeight() / 2; // public void onAnimationEnd(Animator animation) {
int cy = view.getHeight(); // super.onAnimationEnd(animation);
// view.setVisibility(View.GONE);
// get the initial radius for the clipping circle // }
float initialRadius = (float) Math.hypot(cx, cy); // });
//
// create the animation (the final radius is zero) // // start the animation
Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0f); // anim.start();
// }
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});
// start the animation
anim.start();
}
private void setupOptions(final Boolean show) { private void setupOptions(final Boolean show) {
if (!show) { if (!show) {
@ -1536,7 +1538,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
binding.date.setVisibility(View.GONE); binding.date.setVisibility(View.GONE);
binding.comment.setVisibility(View.GONE); binding.comment.setVisibility(View.GONE);
binding.captionToggle.setVisibility(View.GONE); binding.captionToggle.setVisibility(View.GONE);
binding.playerControlsToggle.setVisibility(View.GONE); // binding.playerControlsToggle.setVisibility(View.GONE);
binding.like.setVisibility(View.GONE); binding.like.setVisibility(View.GONE);
binding.save.setVisibility(View.GONE); binding.save.setVisibility(View.GONE);
binding.share.setVisibility(View.GONE); binding.share.setVisibility(View.GONE);
@ -1547,10 +1549,10 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
if (options != null && !options.isEmpty()) { if (options != null && !options.isEmpty()) {
binding.options.setVisibility(View.GONE); binding.options.setVisibility(View.GONE);
} }
wasControlsVisible = binding.playerControls.getRoot().getVisibility() == View.VISIBLE; // wasControlsVisible = binding.playerControls.getRoot().getVisibility() == View.VISIBLE;
if (wasControlsVisible) { // if (wasControlsVisible) {
hidePlayerControls(); // hidePlayerControls();
} // }
return; return;
} }
if (media.getUser() != null) { if (media.getUser() != null) {
@ -1584,12 +1586,12 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
binding.save.setVisibility(View.VISIBLE); binding.save.setVisibility(View.VISIBLE);
} }
if (video) { if (video) {
binding.playerControlsToggle.setVisibility(View.VISIBLE); // binding.playerControlsToggle.setVisibility(View.VISIBLE);
binding.viewsCount.setVisibility(View.VISIBLE); binding.viewsCount.setVisibility(View.VISIBLE);
} }
if (wasControlsVisible) { // if (wasControlsVisible) {
showPlayerControls(); // showPlayerControls();
} // }
if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) { if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
binding.mediaCounter.setVisibility(View.VISIBLE); binding.mediaCounter.setVisibility(View.VISIBLE);
} }

View File

@ -164,7 +164,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:visibility="gone"> tools:visibility="visible">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:id="@+id/caption_parent" android:id="@+id/caption_parent"
@ -251,16 +251,16 @@
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
<include <!--<include-->
android:id="@+id/player_controls" <!-- android:id="@+id/player_controls"-->
layout="@layout/layout_exo_custom_controls" <!-- layout="@layout/layout_exo_custom_controls"-->
android:layout_width="0dp" <!-- android:layout_width="0dp"-->
android:layout_height="wrap_content" <!-- android:layout_height="wrap_content"-->
android:visibility="gone" <!-- android:visibility="gone"-->
app:layout_constraintBottom_toTopOf="@id/bottom_bg_barrier" <!-- app:layout_constraintBottom_toTopOf="@id/bottom_bg_barrier"-->
app:layout_constraintEnd_toEndOf="parent" <!-- app:layout_constraintEnd_toEndOf="parent"-->
app:layout_constraintStart_toStartOf="parent" <!-- app:layout_constraintStart_toStartOf="parent"-->
tools:visibility="gone" /> <!-- tools:visibility="gone" />-->
<View <View
android:id="@+id/bottom_bg" android:id="@+id/bottom_bg"
@ -396,29 +396,29 @@
app:iconSize="24dp" app:iconSize="24dp"
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/player_controls_toggle" app:layout_constraintEnd_toStartOf="@id/save"
app:layout_constraintStart_toEndOf="@id/like" app:layout_constraintStart_toEndOf="@id/like"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier" app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300" app:rippleColor="@color/grey_300"
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.button.MaterialButton <!--<com.google.android.material.button.MaterialButton-->
android:id="@+id/player_controls_toggle" <!-- android:id="@+id/player_controls_toggle"-->
style="@style/Widget.MaterialComponents.Button.TextButton" <!-- style="@style/Widget.MaterialComponents.Button.TextButton"-->
android:layout_width="0dp" <!-- android:layout_width="0dp"-->
android:layout_height="48dp" <!-- android:layout_height="48dp"-->
android:visibility="gone" <!-- android:visibility="gone"-->
app:icon="@drawable/ic_play_circle_outline_24" <!-- app:icon="@drawable/ic_play_circle_outline_24"-->
app:iconGravity="textStart" <!-- app:iconGravity="textStart"-->
app:iconPadding="0dp" <!-- app:iconPadding="0dp"-->
app:iconSize="24dp" <!-- app:iconSize="24dp"-->
app:iconTint="@color/white" <!-- app:iconTint="@color/white"-->
app:layout_constraintBottom_toBottomOf="parent" <!-- app:layout_constraintBottom_toBottomOf="parent"-->
app:layout_constraintEnd_toStartOf="@id/save" <!-- app:layout_constraintEnd_toStartOf="@id/save"-->
app:layout_constraintStart_toEndOf="@id/comment" <!-- app:layout_constraintStart_toEndOf="@id/comment"-->
app:layout_constraintTop_toBottomOf="@id/buttons_barrier" <!-- app:layout_constraintTop_toBottomOf="@id/buttons_barrier"-->
app:rippleColor="@color/grey_300" <!-- app:rippleColor="@color/grey_300"-->
tools:visibility="visible" /> <!-- tools:visibility="visible" />-->
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/save" android:id="@+id/save"
@ -433,7 +433,7 @@
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/share" app:layout_constraintEnd_toStartOf="@id/share"
app:layout_constraintStart_toEndOf="@id/player_controls_toggle" app:layout_constraintStart_toEndOf="@id/comment"
app:layout_constraintTop_toBottomOf="@id/buttons_barrier" app:layout_constraintTop_toBottomOf="@id/buttons_barrier"
app:rippleColor="@color/grey_300" app:rippleColor="@color/grey_300"
tools:visibility="visible" /> tools:visibility="visible" />

View File

@ -3,52 +3,83 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent">
android:background="@color/black_a80" <!-- android:padding="8dp"
android:padding="8dp"> android:background="@color/black_a80"-->
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/exo_black_opacity_60"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--<androidx.constraintlayout.widget.Barrier-->
<!-- android:id="@+id/top_barrier"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="0dp"-->
<!-- app:barrierDirection="top" />-->
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/from_time" android:id="@+id/exo_position"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/white" android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/play_pause" app:layout_constraintBottom_toBottomOf="@id/exo_progress"
app:layout_constraintEnd_toStartOf="@id/timeline" app:layout_constraintEnd_toStartOf="@id/exo_progress"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@id/exo_progress"
tools:text="0:00" /> tools:text="0:00" />
<com.google.android.material.slider.Slider <!--<com.google.android.material.slider.Slider-->
android:id="@+id/timeline" <!-- android:id="@+id/timeline"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:contentDescription="@string/player_timeline_desc"-->
<!-- android:enabled="false"-->
<!-- android:value="0"-->
<!-- android:valueFrom="0.0"-->
<!-- android:valueTo="1.0"-->
<!-- app:labelStyle="@style/Widget.MaterialComponents.Tooltip.ExoPlayer"-->
<!-- app:layout_constraintBottom_toTopOf="@id/play_pause"-->
<!-- app:layout_constraintEnd_toStartOf="@id/to_time"-->
<!-- app:layout_constraintStart_toEndOf="@id/from_time"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:thumbColor="@color/white"-->
<!-- app:trackColorActive="@color/white"-->
<!-- app:trackColorInactive="@color/grey_800" />-->
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@+id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:contentDescription="@string/player_timeline_desc" app:layout_constraintBottom_toTopOf="@id/progress_barrier"
android:enabled="false" app:layout_constraintEnd_toStartOf="@id/exo_duration"
android:value="0" app:layout_constraintStart_toEndOf="@id/exo_position"
android:valueFrom="0.0" app:layout_constraintVertical_bias="1"
android:valueTo="1.0" app:layout_constraintVertical_chainStyle="packed" />
app:labelStyle="@style/Widget.MaterialComponents.Tooltip.ExoPlayer"
app:layout_constraintBottom_toTopOf="@id/play_pause"
app:layout_constraintEnd_toStartOf="@id/to_time"
app:layout_constraintStart_toEndOf="@id/from_time"
app:layout_constraintTop_toTopOf="parent"
app:thumbColor="@color/white"
app:trackColorActive="@color/white"
app:trackColorInactive="@color/grey_800" />
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/to_time" android:id="@+id/exo_duration"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/white" android:textColor="@color/white"
app:layout_constraintBottom_toTopOf="@id/play_pause" app:layout_constraintBottom_toBottomOf="@id/exo_progress"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/timeline" app:layout_constraintStart_toEndOf="@id/exo_progress"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="@id/exo_progress"
tools:text="0:00" /> tools:text="0:00" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/progress_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/rew_with_amount" android:id="@+id/exo_rew_with_amount"
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple" style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -56,40 +87,46 @@
app:icon="@drawable/ic_replay_5_24_states" app:icon="@drawable/ic_replay_5_24_states"
app:iconSize="24dp" app:iconSize="24dp"
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintEnd_toStartOf="@id/play_pause" app:layout_constraintEnd_toStartOf="@id/exo_play_pause"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/timeline" app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:enabled="false" tools:enabled="false"
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.button.MaterialButton <!--
android:id="@+id/play_pause"
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple" style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:icon="@drawable/ic_play_states" app:icon="@drawable/ic_play_states"
app:iconSize="24dp" app:iconSize="24dp"
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" -->
app:layout_constraintEnd_toStartOf="@id/ff_with_amount" <androidx.appcompat.widget.AppCompatImageView
app:layout_constraintStart_toEndOf="@id/rew_with_amount" android:id="@+id/exo_play_pause"
app:layout_constraintTop_toBottomOf="@id/timeline" android:layout_width="0dp"
android:layout_height="wrap_content"
android:contentDescription="@string/exo_controls_play_description"
android:padding="@dimen/exo_icon_padding"
android:scaleType="fitCenter"
android:src="@drawable/exo_styled_controls_play"
app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintEnd_toStartOf="@id/exo_ffwd_with_amount"
app:layout_constraintStart_toEndOf="@id/exo_rew_with_amount"
app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:enabled="false" tools:enabled="false"
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/ff_with_amount" android:id="@+id/exo_ffwd_with_amount"
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple" style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:icon="@drawable/ic_forward_5_24_states" app:icon="@drawable/ic_forward_5_24_states"
app:iconSize="24dp" app:iconSize="24dp"
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintEnd_toStartOf="@id/mute" app:layout_constraintEnd_toStartOf="@id/mute"
app:layout_constraintStart_toEndOf="@id/play_pause" app:layout_constraintStart_toEndOf="@id/exo_play_pause"
app:layout_constraintTop_toBottomOf="@id/timeline" app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:enabled="false" tools:enabled="false"
tools:visibility="visible" /> tools:visibility="visible" />
@ -101,25 +138,47 @@
app:icon="@drawable/ic_volume_off_24_states" app:icon="@drawable/ic_volume_off_24_states"
app:iconSize="24dp" app:iconSize="24dp"
app:iconTint="@color/white" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintEnd_toStartOf="@id/speed" app:layout_constraintEnd_toStartOf="@id/exo_settings"
app:layout_constraintStart_toEndOf="@id/ff_with_amount" app:layout_constraintStart_toEndOf="@id/exo_ffwd_with_amount"
app:layout_constraintTop_toBottomOf="@id/timeline" app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:enabled="false" tools:enabled="false"
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/speed" android:id="@+id/exo_settings"
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple" style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/one_x" app:icon="@drawable/exo_ic_settings"
android:textAllCaps="false" app:iconSize="24dp"
android:textColor="@drawable/speed_text_color_states" app:iconTint="@color/white"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/bottom_barrier"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/mute" app:layout_constraintStart_toEndOf="@id/mute"
app:layout_constraintTop_toBottomOf="@id/timeline" app:layout_constraintTop_toBottomOf="@id/progress_barrier"
tools:enabled="false" tools:enabled="false"
tools:visibility="visible" /> tools:visibility="visible" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/bottom_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_end="200dp" />
<!--<com.google.android.material.button.MaterialButton-->
<!-- android:id="@+id/speed"-->
<!-- style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="@string/one_x"-->
<!-- android:textAllCaps="false"-->
<!-- android:textColor="@drawable/speed_text_color_states"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toEndOf="@id/mute"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- tools:enabled="false"-->
<!-- tools:visibility="visible" />-->
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -25,11 +25,28 @@
app:srcCompat="@drawable/ic_video_24" /> app:srcCompat="@drawable/ic_video_24" />
</FrameLayout> </FrameLayout>
<com.google.android.exoplayer2.ui.StyledPlayerView <FrameLayout
android:id="@+id/playerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:layout_gravity="center"
app:resize_mode="fit" <com.google.android.exoplayer2.ui.StyledPlayerView
app:show_timeout="1000" /> android:id="@+id/playerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
app:animation_enabled="false"
app:controller_layout_id="@layout/layout_exo_custom_controls"
app:resize_mode="fit"
app:show_timeout="1500"
app:use_controller="true" />
<!--<com.google.android.exoplayer2.ui.StyledPlayerControlView-->
<!-- android:id="@+id/controls"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- app:controller_layout_id="@layout/layout_exo_custom_controls"-->
<!-- app:show_fastforward_button="false"-->
<!-- app:show_rewind_button="false"-->
<!-- app:show_timeout="3000" />-->
</FrameLayout>
</ViewSwitcher> </ViewSwitcher>