Added textual tab indicator to player screen (#4731)

This commit is contained in:
ByteHamster 2021-01-01 18:49:03 +01:00 committed by GitHub
parent f3c76e7677
commit 7c93bc5140
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 143 deletions

View File

@ -22,6 +22,8 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.CastEnabledActivity;
import de.danoeh.antennapod.activity.MainActivity;
@ -43,7 +45,6 @@ import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.SleepTimerDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.PagerIndicatorView;
import de.danoeh.antennapod.view.PlaybackSpeedIndicatorView;
import io.reactivex.Maybe;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -74,7 +75,6 @@ public class AudioPlayerFragment extends Fragment implements
PlaybackSpeedIndicatorView butPlaybackSpeed;
TextView txtvPlaybackSpeed;
private ViewPager2 pager;
private PagerIndicatorView pageIndicator;
private TextView txtvPosition;
private TextView txtvLength;
private SeekBar sbPosition;
@ -90,6 +90,8 @@ public class AudioPlayerFragment extends Fragment implements
private PlaybackController controller;
private Disposable disposable;
private boolean showTimeLeft;
private boolean hasChapters = false;
private TabLayoutMediator tabLayoutMediator;
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@ -141,13 +143,37 @@ public class AudioPlayerFragment extends Fragment implements
});
}
});
pageIndicator = root.findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
pageIndicator.setOnClickListener(v ->
pager.setCurrentItem((pager.getCurrentItem() + 1) % NUM_CONTENT_FRAGMENTS));
TabLayout tabLayout = root.findViewById(R.id.sliding_tabs);
tabLayoutMediator = new TabLayoutMediator(tabLayout, pager, (tab, position) -> {
tab.view.setAlpha(1.0f);
switch (position) {
case POS_COVER:
tab.setText(R.string.cover_label);
break;
case POS_DESCR:
tab.setText(R.string.description_label);
break;
case POS_CHAPTERS:
tab.setText(R.string.chapters_label);
if (!hasChapters) {
tab.view.setAlpha(0.5f);
}
break;
default:
break;
}
});
tabLayoutMediator.attach();
return root;
}
public void setHasChapters(boolean hasChapters) {
this.hasChapters = hasChapters;
tabLayoutMediator.detach();
tabLayoutMediator.attach();
}
public View getExternalPlayerHolder() {
return getView().findViewById(R.id.playerFragment);
}
@ -362,10 +388,6 @@ public class AudioPlayerFragment extends Fragment implements
setupOptionsMenu(media);
}
public void setHasChapters(boolean hasChapters) {
pageIndicator.setDisabledPage(hasChapters ? -1 : 2);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

View File

@ -1,124 +0,0 @@
package de.danoeh.antennapod.view;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.util.Locale;
public class PagerIndicatorView extends View {
private final Paint paint = new Paint();
private float position = 0;
private int numPages = 0;
private int disabledPage = -1;
private int circleColor = 0;
private int circleColorHighlight = -1;
private boolean isLocaleRtl = false;
public PagerIndicatorView(Context context) {
super(context);
setup();
}
public PagerIndicatorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setup();
}
public PagerIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
private void setup() {
isLocaleRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
== ViewCompat.LAYOUT_DIRECTION_RTL;
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
int[] colorAttrs = new int[]{android.R.attr.textColorSecondary};
TypedArray a = getContext().obtainStyledAttributes(colorAttrs);
circleColorHighlight = a.getColor(0, 0xffffffff);
circleColor = (Integer) new ArgbEvaluator().evaluate(0.8f, 0x00ffffff, circleColorHighlight);
a.recycle();
}
/**
* Visual and logical position distinction only happens in RTL locales (e.g. Persian)
* where pages positions are flipped thus it does nothing in LTR locales (e.g. English)
*/
private float logicalPositionToVisual(float position) {
return isLocaleRtl ? numPages - 1 - position : position;
}
public void setViewPager(ViewPager2 pager) {
numPages = pager.getAdapter().getItemCount();
pager.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
numPages = pager.getAdapter().getItemCount();
invalidate();
}
});
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
PagerIndicatorView.this.position = logicalPositionToVisual(
position + positionOffset);
invalidate();
}
});
}
public void setDisabledPage(int disabledPage) {
this.disabledPage = (int) logicalPositionToVisual(disabledPage);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < numPages; i++) {
if ((int) Math.floor(position) == i) {
// This is the current dot
drawCircle(canvas, i, (float) (1 - (position - Math.floor(position))));
} else if ((int) Math.ceil(position) == i) {
// This is the next dot
drawCircle(canvas, i, (float) (position - Math.floor(position)));
} else {
drawCircle(canvas, i, 0);
}
}
}
private void drawCircle(Canvas canvas, int position, float frac) {
float availableHeight = canvas.getHeight() - getPaddingTop() - getPaddingBottom();
float circleRadiusSmall = availableHeight * 0.26f;
float circleRadiusBig = availableHeight * 0.35f;
float circleRadiusDelta = (circleRadiusBig - circleRadiusSmall);
float start = 0.5f * (canvas.getWidth() - numPages * 1.5f * availableHeight);
paint.setStrokeWidth(availableHeight * 0.3f);
if (position == disabledPage) {
paint.setStyle(Paint.Style.STROKE);
} else {
paint.setStyle(Paint.Style.FILL_AND_STROKE);
}
paint.setColor((Integer) new ArgbEvaluator().evaluate(frac, circleColor, circleColorHighlight));
canvas.drawCircle(start + (position * 1.5f + 0.75f) * availableHeight, 0.5f * availableHeight + getPaddingTop(),
circleRadiusSmall + frac * circleRadiusDelta, paint);
}
}

View File

@ -15,15 +15,15 @@
app:navigationIcon="?homeAsUpIndicator"
android:id="@+id/toolbar"/>
<de.danoeh.antennapod.view.PagerIndicatorView
android:id="@+id/page_indicator"
android:layout_height="16dp"
android:layout_width="40dp"
android:layout_marginTop="-12dp"
android:padding="4dp"
<com.google.android.material.tabs.TabLayout
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
android:contentDescription="@string/switch_pages"
android:layout_centerHorizontal="true"/>
android:background="?android:attr/windowBackground"
app:tabBackground="?attr/selectableItemBackground"
app:tabMode="fixed"
app:tabGravity="fill"/>
<FrameLayout
android:id="@+id/playerFragment"
@ -39,7 +39,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_above="@id/playtime_layout"
android:layout_below="@id/toolbar"
android:layout_below="@id/sliding_tabs"
android:foreground="?android:windowContentOverlay"
android:layout_marginBottom="12dp"/>