mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-12-23 05:16:58 +00:00
Handle multiple videos in PostViewV2Fragment. Should fix https://github.com/austinhuang0131/barinsta/issues/337 and also fix videos playing after closing view.
This commit is contained in:
parent
6b370ca251
commit
dccfcaf78a
@ -22,7 +22,7 @@ public final class SliderItemsAdapter extends ListAdapter<PostChild, SliderItemV
|
||||
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener;
|
||||
private final boolean loadVideoOnItemClick;
|
||||
private final SliderCallback sliderCallback;
|
||||
private final awais.instagrabber.databinding.LayoutExoCustomControlsBinding controlsBinding;
|
||||
private final LayoutExoCustomControlsBinding controlsBinding;
|
||||
|
||||
private static final DiffUtil.ItemCallback<PostChild> DIFF_CALLBACK = new DiffUtil.ItemCallback<PostChild>() {
|
||||
@Override
|
||||
|
@ -135,6 +135,16 @@ public class SliderVideoViewHolder extends SliderItemViewHolder {
|
||||
videoPlayerViewHelper.releasePlayer();
|
||||
}
|
||||
|
||||
public void resetPlayerTimeline() {
|
||||
if (videoPlayerViewHelper == null) return;
|
||||
videoPlayerViewHelper.resetTimeline();
|
||||
}
|
||||
|
||||
public void removeCallbacks() {
|
||||
if (videoPlayerViewHelper == null) return;
|
||||
videoPlayerViewHelper.removeCallbacks();
|
||||
}
|
||||
|
||||
// private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) {
|
||||
// final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams();
|
||||
// final int deviceWidth = Utils.displayMetrics.widthPixels;
|
||||
|
@ -10,6 +10,7 @@ import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.view.ContextThemeWrapper;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
@ -26,6 +27,8 @@ import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.audio.AudioListener;
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.material.slider.LabelFormatter;
|
||||
import com.google.android.material.slider.Slider;
|
||||
|
||||
import awais.instagrabber.R;
|
||||
import awais.instagrabber.databinding.LayoutExoCustomControlsBinding;
|
||||
@ -39,6 +42,8 @@ import static com.google.android.exoplayer2.Player.STATE_READY;
|
||||
|
||||
public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
private static final String TAG = "VideoPlayerViewHelper";
|
||||
private static final long INITIAL_DELAY = 0;
|
||||
private static final long RECURRING_DELAY = 60;
|
||||
|
||||
private final Context context;
|
||||
private final awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding binding;
|
||||
@ -52,6 +57,62 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
private SimpleExoPlayer player;
|
||||
private PopupMenu speedPopup;
|
||||
private Runnable positionChecker;
|
||||
|
||||
private final Handler positionUpdateHandler = new Handler();
|
||||
private final Player.EventListener listener = new Player.EventListener() {
|
||||
@Override
|
||||
public void onPlaybackStateChanged(final int state) {
|
||||
switch (state) {
|
||||
case Player.STATE_BUFFERING:
|
||||
case STATE_IDLE:
|
||||
case STATE_ENDED:
|
||||
positionUpdateHandler.removeCallbacks(positionChecker);
|
||||
return;
|
||||
case STATE_READY:
|
||||
setupTimeline();
|
||||
positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
|
||||
updatePlayPauseDrawable(playWhenReady);
|
||||
}
|
||||
};
|
||||
private final AudioListener audioListener = new AudioListener() {
|
||||
@Override
|
||||
public void onVolumeChanged(final float volume) {
|
||||
updateMuteIcon(volume);
|
||||
}
|
||||
};
|
||||
private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> {
|
||||
if (!fromUser) return;
|
||||
long actualValue = (long) value;
|
||||
if (actualValue < 0) {
|
||||
actualValue = 0;
|
||||
} else if (actualValue > player.getDuration()) {
|
||||
actualValue = player.getDuration();
|
||||
}
|
||||
player.seekTo(actualValue);
|
||||
};
|
||||
private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady());
|
||||
private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value);
|
||||
private final View.OnClickListener muteOnClickListener = v -> toggleMute();
|
||||
private final View.OnClickListener rewOnClickListener = v -> {
|
||||
final long positionMs = player.getCurrentPosition() - 5000;
|
||||
player.seekTo(positionMs < 0 ? 0 : positionMs);
|
||||
};
|
||||
private final View.OnClickListener ffOnClickListener = v -> {
|
||||
long positionMs = player.getCurrentPosition() + 5000;
|
||||
long duration = player.getDuration();
|
||||
if (duration == TIME_UNSET) {
|
||||
duration = 0;
|
||||
}
|
||||
player.seekTo(Math.min(positionMs, duration));
|
||||
};
|
||||
private final View.OnClickListener showMenu = this::showMenu;
|
||||
|
||||
public VideoPlayerViewHelper(@NonNull final Context context,
|
||||
@NonNull final LayoutVideoPlayerWithThumbnailBinding binding,
|
||||
@ -130,6 +191,10 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
player = new SimpleExoPlayer.Builder(context)
|
||||
.setLooper(Looper.getMainLooper())
|
||||
.build();
|
||||
positionChecker = new PositionCheckRunnable(positionUpdateHandler,
|
||||
player,
|
||||
controlsBinding.timeline,
|
||||
controlsBinding.fromTime);
|
||||
player.addListener(this);
|
||||
player.setVolume(initialVolume);
|
||||
player.setPlayWhenReady(true);
|
||||
@ -148,87 +213,22 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
binding.playerView.setUseController(false);
|
||||
if (player == null) {
|
||||
enableControls(false);
|
||||
controlsBinding.playPause.setEnabled(true);
|
||||
controlsBinding.playPause.setOnClickListener(v -> binding.thumbnailParent.performClick());
|
||||
// controlsBinding.playPause.setEnabled(true);
|
||||
// controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent));
|
||||
return;
|
||||
}
|
||||
enableControls(true);
|
||||
final Handler handler = new Handler();
|
||||
final long initialDelay = 0;
|
||||
final long recurringDelay = 60;
|
||||
final Runnable positionChecker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handler.removeCallbacks(this);
|
||||
if (player == null) return;
|
||||
final long currentPosition = player.getCurrentPosition();
|
||||
final long duration = player.getDuration();
|
||||
if (duration == TIME_UNSET) {
|
||||
controlsBinding.timeline.setValueFrom(0);
|
||||
controlsBinding.timeline.setValueTo(0);
|
||||
controlsBinding.timeline.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
controlsBinding.timeline.setValue(Math.min(currentPosition, duration));
|
||||
controlsBinding.fromTime.setText(TextUtils.millisToTimeString(currentPosition));
|
||||
handler.postDelayed(this, recurringDelay);
|
||||
}
|
||||
};
|
||||
updatePlayPauseDrawable(player.getPlayWhenReady());
|
||||
updateMuteIcon(player.getVolume());
|
||||
player.addListener(new Player.EventListener() {
|
||||
@Override
|
||||
public void onPlaybackStateChanged(final int state) {
|
||||
switch (state) {
|
||||
case Player.STATE_BUFFERING:
|
||||
case STATE_IDLE:
|
||||
case STATE_ENDED:
|
||||
handler.removeCallbacks(positionChecker);
|
||||
return;
|
||||
case STATE_READY:
|
||||
setupTimeline();
|
||||
handler.postDelayed(positionChecker, initialDelay);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) {
|
||||
updatePlayPauseDrawable(playWhenReady);
|
||||
}
|
||||
});
|
||||
player.addAudioListener(new AudioListener() {
|
||||
@Override
|
||||
public void onVolumeChanged(final float volume) {
|
||||
updateMuteIcon(volume);
|
||||
}
|
||||
});
|
||||
controlsBinding.timeline.addOnChangeListener((slider, value, fromUser) -> {
|
||||
if (!fromUser) return;
|
||||
long actualValue = (long) value;
|
||||
if (actualValue < 0) {
|
||||
actualValue = 0;
|
||||
} else if (actualValue > player.getDuration()) {
|
||||
actualValue = player.getDuration();
|
||||
}
|
||||
player.seekTo(actualValue);
|
||||
});
|
||||
controlsBinding.timeline.setLabelFormatter(value -> TextUtils.millisToTimeString((long) value));
|
||||
controlsBinding.playPause.setOnClickListener(v -> player.setPlayWhenReady(!player.getPlayWhenReady()));
|
||||
controlsBinding.mute.setOnClickListener(v -> toggleMute());
|
||||
controlsBinding.rewWithAmount.setOnClickListener(v -> {
|
||||
final long positionMs = player.getCurrentPosition() - 5000;
|
||||
player.seekTo(positionMs < 0 ? 0 : positionMs);
|
||||
});
|
||||
controlsBinding.ffWithAmount.setOnClickListener(v -> {
|
||||
long positionMs = player.getCurrentPosition() + 5000;
|
||||
long duration = player.getDuration();
|
||||
if (duration == TIME_UNSET) {
|
||||
duration = 0;
|
||||
}
|
||||
player.seekTo(Math.min(positionMs, duration));
|
||||
});
|
||||
controlsBinding.speed.setOnClickListener(this::showMenu);
|
||||
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() {
|
||||
@ -242,12 +242,18 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
|
||||
private void enableControls(final boolean enable) {
|
||||
controlsBinding.speed.setEnabled(enable);
|
||||
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);
|
||||
}
|
||||
|
||||
public void showMenu(View anchor) {
|
||||
@ -302,10 +308,10 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
|
||||
private void updateMuteIcon(final float volume) {
|
||||
if (volume == 0) {
|
||||
controlsBinding.mute.setIconResource(R.drawable.ic_volume_off_24);
|
||||
controlsBinding.mute.setIconResource(R.drawable.ic_volume_off_24_states);
|
||||
return;
|
||||
}
|
||||
controlsBinding.mute.setIconResource(R.drawable.ic_volume_up_24);
|
||||
controlsBinding.mute.setIconResource(R.drawable.ic_volume_up_24_states);
|
||||
}
|
||||
|
||||
private void updatePlayPauseDrawable(final boolean playWhenReady) {
|
||||
@ -313,7 +319,7 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24);
|
||||
return;
|
||||
}
|
||||
controlsBinding.playPause.setIconResource(R.drawable.ic_play_arrow_24);
|
||||
controlsBinding.playPause.setIconResource(R.drawable.ic_play_states);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -338,23 +344,88 @@ public class VideoPlayerViewHelper implements Player.EventListener {
|
||||
return vol;
|
||||
}
|
||||
|
||||
public void togglePlayback() {
|
||||
if (player == null) return;
|
||||
final int playbackState = player.getPlaybackState();
|
||||
if (playbackState == STATE_IDLE || playbackState == STATE_ENDED) return;
|
||||
final boolean playWhenReady = player.getPlayWhenReady();
|
||||
player.setPlayWhenReady(!playWhenReady);
|
||||
}
|
||||
// public void togglePlayback() {
|
||||
// if (player == null) return;
|
||||
// final int playbackState = player.getPlaybackState();
|
||||
// if (playbackState == STATE_IDLE || playbackState == STATE_ENDED) return;
|
||||
// final boolean playWhenReady = player.getPlayWhenReady();
|
||||
// player.setPlayWhenReady(!playWhenReady);
|
||||
// }
|
||||
|
||||
public void releasePlayer() {
|
||||
if (player == null) return;
|
||||
player.release();
|
||||
player = null;
|
||||
if (positionUpdateHandler != null && positionChecker != null) {
|
||||
positionUpdateHandler.removeCallbacks(positionChecker);
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (player == null) return;
|
||||
player.pause();
|
||||
if (positionUpdateHandler != null && positionChecker != null) {
|
||||
positionUpdateHandler.removeCallbacks(positionChecker);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetTimeline() {
|
||||
if (player == null) {
|
||||
enableControls(false);
|
||||
return;
|
||||
}
|
||||
setupTimeline();
|
||||
final long currentPosition = player.getCurrentPosition();
|
||||
controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration()));
|
||||
setupControls();
|
||||
}
|
||||
|
||||
public void removeCallbacks() {
|
||||
if (player != null) {
|
||||
player.removeListener(listener);
|
||||
player.removeAudioListener(audioListener);
|
||||
}
|
||||
controlsBinding.timeline.removeOnChangeListener(onChangeListener);
|
||||
controlsBinding.timeline.setLabelFormatter(null);
|
||||
controlsBinding.playPause.setOnClickListener(null);
|
||||
controlsBinding.mute.setOnClickListener(null);
|
||||
controlsBinding.rewWithAmount.setOnClickListener(null);
|
||||
controlsBinding.ffWithAmount.setOnClickListener(null);
|
||||
controlsBinding.speed.setOnClickListener(null);
|
||||
}
|
||||
|
||||
private static class PositionCheckRunnable implements Runnable {
|
||||
private final Handler positionUpdateHandler;
|
||||
private final SimpleExoPlayer player;
|
||||
private final Slider timeline;
|
||||
private final AppCompatTextView fromTime;
|
||||
|
||||
public PositionCheckRunnable(final Handler positionUpdateHandler,
|
||||
final SimpleExoPlayer simpleExoPlayer,
|
||||
final Slider slider,
|
||||
final AppCompatTextView fromTime) {
|
||||
this.positionUpdateHandler = positionUpdateHandler;
|
||||
this.player = simpleExoPlayer;
|
||||
this.timeline = slider;
|
||||
this.fromTime = fromTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
positionUpdateHandler.removeCallbacks(this);
|
||||
if (player == null) return;
|
||||
final long currentPosition = player.getCurrentPosition();
|
||||
final long duration = player.getDuration();
|
||||
if (duration == TIME_UNSET) {
|
||||
timeline.setValueFrom(0);
|
||||
timeline.setValueTo(0);
|
||||
timeline.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
timeline.setValue(Math.min(currentPosition, duration));
|
||||
fromTime.setText(TextUtils.millisToTimeString(currentPosition));
|
||||
positionUpdateHandler.postDelayed(this, RECURRING_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
public interface VideoPlayerCallback {
|
||||
|
@ -113,6 +113,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
private int sliderPosition = -1;
|
||||
private DialogInterface.OnShowListener onShowListener;
|
||||
private boolean isLoggedIn;
|
||||
private boolean hasBeenToggled = false;
|
||||
|
||||
private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener = new VerticalDragHelper.OnVerticalDragListener() {
|
||||
|
||||
@ -303,8 +304,8 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
switch (feedModel.getItemType()) {
|
||||
case MEDIA_TYPE_VIDEO:
|
||||
if (videoPlayerViewHelper != null) {
|
||||
@ -870,6 +871,20 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
if (!wasPaused && sharedMainPostElement != null) {
|
||||
addSharedElement(sharedMainPostElement, binding.sliderParent);
|
||||
}
|
||||
final boolean hasVideo = feedModel.getSliderItems()
|
||||
.stream()
|
||||
.anyMatch(postChild -> postChild.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO);
|
||||
if (hasVideo) {
|
||||
final View child = binding.sliderParent.getChildAt(0);
|
||||
if (child instanceof RecyclerView) {
|
||||
((RecyclerView) child).setItemViewCacheSize(feedModel.getSliderItems().size());
|
||||
((RecyclerView) child).addRecyclerListener(holder -> {
|
||||
if (holder instanceof SliderVideoViewHolder) {
|
||||
((SliderVideoViewHolder) holder).releasePlayer();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
sliderItemsAdapter = new SliderItemsAdapter(onVerticalDragListener, binding.playerControls, true, new SliderCallbackAdapter() {
|
||||
@Override
|
||||
public void onThumbnailLoaded(final int position) {
|
||||
@ -879,19 +894,17 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
|
||||
@Override
|
||||
public void onItemClicked(final int position) {
|
||||
toggleDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerPlay(final int position) {
|
||||
if (!detailsVisible) return;
|
||||
toggleDetails();
|
||||
if (!detailsVisible || hasBeenToggled) return;
|
||||
showPlayerControls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerPause(final int position) {
|
||||
if (detailsVisible) return;
|
||||
if (detailsVisible || hasBeenToggled) return;
|
||||
toggleDetails();
|
||||
}
|
||||
});
|
||||
@ -924,7 +937,22 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
final String text = (position + 1) + "/" + size;
|
||||
binding.mediaCounter.setText(text);
|
||||
final PostChild postChild = feedModel.getSliderItems().get(position);
|
||||
final View view = binding.sliderParent.getChildAt(0);
|
||||
if (prevPosition != -1) {
|
||||
if (view instanceof RecyclerView) {
|
||||
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(prevPosition);
|
||||
if (viewHolder instanceof SliderVideoViewHolder) {
|
||||
((SliderVideoViewHolder) viewHolder).removeCallbacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (postChild.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) {
|
||||
if (view instanceof RecyclerView) {
|
||||
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(position);
|
||||
if (viewHolder instanceof SliderVideoViewHolder) {
|
||||
((SliderVideoViewHolder) viewHolder).resetPlayerTimeline();
|
||||
}
|
||||
}
|
||||
enablePlayerControls(true);
|
||||
return;
|
||||
}
|
||||
@ -1052,6 +1080,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
hideCaption();
|
||||
// previously invisible view
|
||||
View view = binding.playerControls.getRoot();
|
||||
if (view != null && view.getVisibility() == View.VISIBLE) {
|
||||
return;
|
||||
}
|
||||
if (!ViewCompat.isAttachedToWindow(view)) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
@ -1076,6 +1107,9 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
private void hidePlayerControls() {
|
||||
// previously visible view
|
||||
final View view = binding.playerControls.getRoot();
|
||||
if (view != null && view.getVisibility() == View.GONE) {
|
||||
return;
|
||||
}
|
||||
if (!ViewCompat.isAttachedToWindow(view)) {
|
||||
view.setVisibility(View.GONE);
|
||||
return;
|
||||
@ -1106,6 +1140,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment {
|
||||
}
|
||||
|
||||
private void toggleDetails() {
|
||||
hasBeenToggled = true;
|
||||
binding.getRoot().post(() -> {
|
||||
TransitionManager.beginDelayedTransition(binding.getRoot());
|
||||
if (detailsVisible) {
|
||||
|
15
app/src/main/res/drawable/ic_forward_5_24_a50.xml
Normal file
15
app/src/main/res/drawable/ic_forward_5_24_a50.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18,13c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6s2.69,-6 6,-6v4l5,-5l-5,-5v4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8c4.42,0 8,-3.58 8,-8H18z" />
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12.03,15.38c-0.44,0 -0.58,-0.31 -0.6,-0.56h-0.84c0.03,0.85 0.79,1.25 1.44,1.25c0.93,0 1.44,-0.63 1.44,-1.43c0,-1.33 -0.97,-1.44 -1.3,-1.44c-0.2,0 -0.43,0.05 -0.64,0.16l0.11,-0.92h1.7v-0.71h-2.39l-0.25,2.17l0.67,0.17c0.13,-0.13 0.28,-0.23 0.57,-0.23c0.4,0 0.69,0.23 0.69,0.75C12.62,14.64 12.65,15.38 12.03,15.38z" />
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_forward_5_24_states.xml
Normal file
5
app/src/main/res/drawable/ic_forward_5_24_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_forward_5_24_a50" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/ic_forward_5_24" android:state_enabled="true" />
|
||||
</selector>
|
11
app/src/main/res/drawable/ic_play_arrow_24_a50.xml
Normal file
11
app/src/main/res/drawable/ic_play_arrow_24_a50.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillAlpha="0.5"
|
||||
android:pathData="M8,5v14l11,-7z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_play_states.xml
Normal file
5
app/src/main/res/drawable/ic_play_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_play_arrow_24_a50" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/ic_play_arrow_24" android:state_enabled="true" />
|
||||
</selector>
|
15
app/src/main/res/drawable/ic_replay_5_24_a50.xml
Normal file
15
app/src/main/res/drawable/ic_replay_5_24_a50.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,5V1L7,6l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6H4c0,4.42 3.58,8 8,8s8,-3.58 8,-8S16.42,5 12,5z" />
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10.69,13.9l0.25,-2.17h2.39v0.71h-1.7l-0.11,0.92c0.03,-0.02 0.07,-0.03 0.11,-0.05s0.09,-0.04 0.15,-0.05s0.12,-0.03 0.18,-0.04s0.13,-0.02 0.2,-0.02c0.21,0 0.39,0.03 0.55,0.1s0.3,0.16 0.41,0.28s0.2,0.27 0.25,0.45s0.09,0.38 0.09,0.6c0,0.19 -0.03,0.37 -0.09,0.54s-0.15,0.32 -0.27,0.45s-0.27,0.24 -0.45,0.31s-0.39,0.12 -0.64,0.12c-0.18,0 -0.36,-0.03 -0.53,-0.08s-0.32,-0.14 -0.46,-0.24s-0.24,-0.24 -0.32,-0.39s-0.13,-0.33 -0.13,-0.53h0.84c0.02,0.18 0.08,0.32 0.19,0.41s0.25,0.15 0.42,0.15c0.11,0 0.2,-0.02 0.27,-0.06s0.14,-0.1 0.18,-0.17s0.08,-0.15 0.11,-0.25s0.03,-0.2 0.03,-0.31s-0.01,-0.21 -0.04,-0.31s-0.07,-0.17 -0.13,-0.24s-0.13,-0.12 -0.21,-0.15s-0.19,-0.05 -0.3,-0.05c-0.08,0 -0.15,0.01 -0.2,0.02s-0.11,0.03 -0.15,0.05s-0.08,0.05 -0.12,0.07s-0.07,0.06 -0.1,0.09L10.69,13.9z" />
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_replay_5_24_states.xml
Normal file
5
app/src/main/res/drawable/ic_replay_5_24_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_replay_5_24_a50" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/ic_replay_5_24" android:state_enabled="true" />
|
||||
</selector>
|
11
app/src/main/res/drawable/ic_volume_off_24_a50.xml
Normal file
11
app/src/main/res/drawable/ic_volume_off_24_a50.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z" />
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_volume_off_24_states.xml
Normal file
5
app/src/main/res/drawable/ic_volume_off_24_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_volume_off_24_a50" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/ic_volume_off_24" android:state_enabled="true" />
|
||||
</selector>
|
11
app/src/main/res/drawable/ic_volume_up_24_a50.xml
Normal file
11
app/src/main/res/drawable/ic_volume_up_24_a50.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillAlpha="0.5"
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" />
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_volume_up_24_states.xml
Normal file
5
app/src/main/res/drawable/ic_volume_up_24_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_volume_up_24_a50" android:state_enabled="false" />
|
||||
<item android:drawable="@drawable/ic_volume_up_24" android:state_enabled="true" />
|
||||
</selector>
|
5
app/src/main/res/drawable/speed_text_color_states.xml
Normal file
5
app/src/main/res/drawable/speed_text_color_states.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/white_a50" android:state_enabled="false" />
|
||||
<item android:color="@color/white" android:state_enabled="true" />
|
||||
</selector>
|
@ -53,13 +53,14 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_replay_5_24"
|
||||
app:icon="@drawable/ic_replay_5_24_states"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/play_pause"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/timeline"
|
||||
tools:enabled="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -67,13 +68,14 @@
|
||||
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_play_arrow_24"
|
||||
app:icon="@drawable/ic_play_states"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/ff_with_amount"
|
||||
app:layout_constraintStart_toEndOf="@id/rew_with_amount"
|
||||
app:layout_constraintTop_toBottomOf="@id/timeline"
|
||||
tools:enabled="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -81,13 +83,14 @@
|
||||
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_forward_5_24"
|
||||
app:icon="@drawable/ic_forward_5_24_states"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/mute"
|
||||
app:layout_constraintStart_toEndOf="@id/play_pause"
|
||||
app:layout_constraintTop_toBottomOf="@id/timeline"
|
||||
tools:enabled="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -95,13 +98,14 @@
|
||||
style="@style/Widget.App.MaterialButton.IconOnly.BorderlessRipple"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_volume_off_24"
|
||||
app:icon="@drawable/ic_volume_off_24_states"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="@color/white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/speed"
|
||||
app:layout_constraintStart_toEndOf="@id/ff_with_amount"
|
||||
app:layout_constraintTop_toBottomOf="@id/timeline"
|
||||
tools:enabled="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -111,10 +115,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/one_x"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/white"
|
||||
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_toBottomOf="@id/timeline"
|
||||
tools:enabled="false"
|
||||
tools:visibility="visible" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -33,6 +33,7 @@
|
||||
<color name="comment_selected">#888888</color>
|
||||
|
||||
<color name="white">#FFFFFF</color>
|
||||
<color name="white_a50">#80FFFFFF</color>
|
||||
|
||||
<color name="black">#000000</color>
|
||||
<color name="black_800">#121212</color>
|
||||
|
Loading…
Reference in New Issue
Block a user