New scroll bar
This commit is contained in:
parent
77f7b1bd5b
commit
24f78d9738
4 changed files with 261 additions and 0 deletions
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Hemanth Savarala.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License v3
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
package code.name.monkey.retromusic.util
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
|
||||||
|
import code.name.monkey.appthemehelper.util.ColorUtil.isColorLight
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper.getPrimaryTextColor
|
||||||
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
|
import code.name.monkey.retromusic.views.PopupBackground
|
||||||
|
import me.zhanghai.android.fastscroll.FastScroller
|
||||||
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
|
import me.zhanghai.android.fastscroll.PopupStyles
|
||||||
|
import me.zhanghai.android.fastscroll.R
|
||||||
|
|
||||||
|
object ThemedFastScroller {
|
||||||
|
fun create(view: ViewGroup): FastScroller {
|
||||||
|
val context = view.context
|
||||||
|
val color = accentColor(context)
|
||||||
|
val textColor = getPrimaryTextColor(context, isColorLight(color))
|
||||||
|
val fastScrollerBuilder = FastScrollerBuilder(view)
|
||||||
|
fastScrollerBuilder.useMd2Style()
|
||||||
|
fastScrollerBuilder.setPopupStyle { popupText ->
|
||||||
|
PopupStyles.MD2.accept(popupText)
|
||||||
|
popupText.background = PopupBackground(context)
|
||||||
|
popupText.setTextColor(textColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fastScrollerBuilder.setThumbDrawable(
|
||||||
|
TintHelper.createTintedDrawable(
|
||||||
|
context,
|
||||||
|
R.drawable.afs_md2_thumb,
|
||||||
|
color
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return fastScrollerBuilder.build()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Hemanth Savarala.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License v3
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package code.name.monkey.retromusic.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.ColorFilter;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Outline;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Path;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
|
import code.name.monkey.appthemehelper.ThemeStore;
|
||||||
|
import code.name.monkey.retromusic.R;
|
||||||
|
|
||||||
|
public class PopupBackground extends Drawable {
|
||||||
|
|
||||||
|
private final int mPaddingEnd;
|
||||||
|
|
||||||
|
private final int mPaddingStart;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Paint mPaint;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Path mPath = new Path();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Matrix mTempMatrix = new Matrix();
|
||||||
|
|
||||||
|
public PopupBackground(@NonNull Context context) {
|
||||||
|
mPaint = new Paint();
|
||||||
|
mPaint.setAntiAlias(true);
|
||||||
|
mPaint.setColor(ThemeStore.Companion.accentColor(context));
|
||||||
|
mPaint.setStyle(Paint.Style.FILL);
|
||||||
|
Resources resources = context.getResources();
|
||||||
|
mPaddingStart = resources.getDimensionPixelOffset(R.dimen.afs_md2_popup_padding_start);
|
||||||
|
mPaddingEnd = resources.getDimensionPixelOffset(R.dimen.afs_md2_popup_padding_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(@NonNull Canvas canvas) {
|
||||||
|
canvas.drawPath(mPath, mPaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOpacity() {
|
||||||
|
return PixelFormat.TRANSLUCENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getOutline(@NonNull Outline outline) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && !mPath.isConvex()) {
|
||||||
|
// The outline path must be convex before Q, but we may run into floating point error
|
||||||
|
// caused by calculation involving sqrt(2) or OEM implementation difference, so in this
|
||||||
|
// case we just omit the shadow instead of crashing.
|
||||||
|
super.getOutline(outline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outline.setConvexPath(mPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getPadding(@NonNull Rect padding) {
|
||||||
|
if (needMirroring()) {
|
||||||
|
padding.set(mPaddingEnd, 0, mPaddingStart, 0);
|
||||||
|
} else {
|
||||||
|
padding.set(mPaddingStart, 0, mPaddingEnd, 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoMirrored() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLayoutDirectionChanged(int layoutDirection) {
|
||||||
|
updatePath();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAlpha(int alpha) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBoundsChange(@NonNull Rect bounds) {
|
||||||
|
updatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean needMirroring() {
|
||||||
|
return DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePath() {
|
||||||
|
|
||||||
|
mPath.reset();
|
||||||
|
|
||||||
|
Rect bounds = getBounds();
|
||||||
|
float width = bounds.width();
|
||||||
|
float height = bounds.height();
|
||||||
|
float r = height / 2;
|
||||||
|
float sqrt2 = (float) Math.sqrt(2);
|
||||||
|
// Ensure we are convex.
|
||||||
|
width = Math.max(r + sqrt2 * r, width);
|
||||||
|
pathArcTo(mPath, r, r, r, 90, 180);
|
||||||
|
float o1X = width - sqrt2 * r;
|
||||||
|
pathArcTo(mPath, o1X, r, r, -90, 45f);
|
||||||
|
float r2 = r / 5;
|
||||||
|
float o2X = width - sqrt2 * r2;
|
||||||
|
pathArcTo(mPath, o2X, r, r2, -45, 90);
|
||||||
|
pathArcTo(mPath, o1X, r, r, 45f, 45f);
|
||||||
|
mPath.close();
|
||||||
|
|
||||||
|
if (needMirroring()) {
|
||||||
|
mTempMatrix.setScale(-1, 1, width / 2, 0);
|
||||||
|
} else {
|
||||||
|
mTempMatrix.reset();
|
||||||
|
}
|
||||||
|
mTempMatrix.postTranslate(bounds.left, bounds.top);
|
||||||
|
mPath.transform(mTempMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pathArcTo(@NonNull Path path, float centerX, float centerY, float radius,
|
||||||
|
float startAngle, float sweepAngle) {
|
||||||
|
path.arcTo(centerX - radius, centerY - radius, centerX + radius, centerY + radius,
|
||||||
|
startAngle, sweepAngle, false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Hemanth Savarala.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License v3
|
||||||
|
*
|
||||||
|
* This is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package code.name.monkey.retromusic.views;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import me.zhanghai.android.fastscroll.FastScroller;
|
||||||
|
|
||||||
|
public class ScrollingViewOnApplyWindowInsetsListener implements View.OnApplyWindowInsetsListener {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Rect mPadding = new Rect();
|
||||||
|
@Nullable
|
||||||
|
private final FastScroller mFastScroller;
|
||||||
|
|
||||||
|
public ScrollingViewOnApplyWindowInsetsListener(@Nullable View view,
|
||||||
|
@Nullable FastScroller fastScroller) {
|
||||||
|
if (view != null) {
|
||||||
|
mPadding.set(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
|
||||||
|
view.getPaddingBottom());
|
||||||
|
}
|
||||||
|
mFastScroller = fastScroller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScrollingViewOnApplyWindowInsetsListener() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public WindowInsets onApplyWindowInsets(@NonNull View view, @NonNull WindowInsets insets) {
|
||||||
|
view.setPadding(mPadding.left + insets.getSystemWindowInsetLeft(), mPadding.top,
|
||||||
|
mPadding.right + insets.getSystemWindowInsetRight(),
|
||||||
|
mPadding.bottom + insets.getSystemWindowInsetBottom());
|
||||||
|
if (mFastScroller != null) {
|
||||||
|
mFastScroller.setPadding(insets.getSystemWindowInsetLeft(), 0,
|
||||||
|
insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
|
||||||
|
}
|
||||||
|
return insets;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue