mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 09:39:25 +03:00
Make fast scroll bar and popup use the theme color
Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
This commit is contained in:
parent
31c84d57e9
commit
a7877ceb41
4 changed files with 208 additions and 4 deletions
|
@ -27,23 +27,59 @@
|
||||||
|
|
||||||
package com.nextcloud.utils.view
|
package com.nextcloud.utils.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import com.owncloud.android.utils.theme.ThemeColorUtils
|
||||||
|
import com.owncloud.android.utils.theme.ThemeDrawableUtils
|
||||||
import me.zhanghai.android.fastscroll.FastScroller
|
import me.zhanghai.android.fastscroll.FastScroller
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
|
import me.zhanghai.android.fastscroll.PopupStyles
|
||||||
|
|
||||||
object FastScroll {
|
object FastScroll {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun applyFastScroll(recyclerView: RecyclerView, viewHelper: FastScroller.ViewHelper? = null) {
|
fun applyFastScroll(
|
||||||
val builder = FastScrollerBuilder(recyclerView).useMd2Style()
|
context: Context,
|
||||||
|
themeColorUtils: ThemeColorUtils,
|
||||||
|
themeDrawableUtils: ThemeDrawableUtils,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHelper: FastScroller.ViewHelper? = null
|
||||||
|
) {
|
||||||
|
val primaryColor = themeColorUtils.primaryColor(context)
|
||||||
|
val builder = FastScrollerBuilder(recyclerView)
|
||||||
|
.useMd2Style()
|
||||||
|
.setThumbDrawable(getThumbDrawable(context, themeDrawableUtils, primaryColor))
|
||||||
|
.setPopupStyle {
|
||||||
|
PopupStyles.MD2.accept(it)
|
||||||
|
it.background = FastScrollPopupBackground(context, primaryColor)
|
||||||
|
}
|
||||||
if (viewHelper != null) {
|
if (viewHelper != null) {
|
||||||
builder.setViewHelper(viewHelper)
|
builder.setViewHelper(viewHelper)
|
||||||
}
|
}
|
||||||
builder.build()
|
builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getThumbDrawable(
|
||||||
|
context: Context,
|
||||||
|
themeDrawableUtils: ThemeDrawableUtils,
|
||||||
|
@ColorInt color: Int
|
||||||
|
): Drawable {
|
||||||
|
val thumbDrawable =
|
||||||
|
ResourcesCompat.getDrawable(
|
||||||
|
context.resources,
|
||||||
|
me.zhanghai.android.fastscroll.R.drawable.afs_md2_thumb,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
themeDrawableUtils.tintDrawable(thumbDrawable, color)
|
||||||
|
return thumbDrawable!!
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun fixAppBarForFastScroll(appBarLayout: AppBarLayout, content: ViewGroup) {
|
fun fixAppBarForFastScroll(appBarLayout: AppBarLayout, content: ViewGroup) {
|
||||||
val contentLayoutInitialPaddingBottom = content.paddingBottom
|
val contentLayoutInitialPaddingBottom = content.paddingBottom
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
/*
|
||||||
|
* Nextcloud Android Library is available under MIT license
|
||||||
|
*
|
||||||
|
* @author Álvaro Brey Vilas
|
||||||
|
* Copyright (C) 2022 Álvaro Brey Vilas
|
||||||
|
* Copyright (C) 2022 Nextcloud GmbH
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.nextcloud.utils.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
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.ColorInt
|
||||||
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied over from [me.zhanghai.android.fastscroll.Md2PopupBackground] on 2022/06/15
|
||||||
|
* and adapted for color changing
|
||||||
|
*/
|
||||||
|
class FastScrollPopupBackground(context: Context, @ColorInt color: Int) : Drawable() {
|
||||||
|
|
||||||
|
private val mPaint: Paint = Paint()
|
||||||
|
private val mPaddingStart: Int
|
||||||
|
private val mPaddingEnd: Int
|
||||||
|
private val mPath = Path()
|
||||||
|
private val mTempMatrix = Matrix()
|
||||||
|
|
||||||
|
init {
|
||||||
|
mPaint.isAntiAlias = true
|
||||||
|
mPaint.color = color
|
||||||
|
mPaint.style = Paint.Style.FILL
|
||||||
|
val resources = context.resources
|
||||||
|
mPaddingStart =
|
||||||
|
resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_start)
|
||||||
|
mPaddingEnd =
|
||||||
|
resources.getDimensionPixelOffset(me.zhanghai.android.fastscroll.R.dimen.afs_md2_popup_padding_end)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun draw(canvas: Canvas) {
|
||||||
|
canvas.drawPath(mPath, mPaint)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setAlpha(alpha: Int) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setColorFilter(colorFilter: ColorFilter?) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isAutoMirrored(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOpacity(): Int {
|
||||||
|
return PixelFormat.TRANSPARENT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldMirrorPath(): Boolean {
|
||||||
|
return DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLayoutDirectionChanged(layoutDirection: Int): Boolean {
|
||||||
|
updatePath()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBoundsChange(bounds: Rect) {
|
||||||
|
updatePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
private fun updatePath() {
|
||||||
|
mPath.reset()
|
||||||
|
val bounds = bounds
|
||||||
|
var width = bounds.width().toFloat()
|
||||||
|
val height = bounds.height().toFloat()
|
||||||
|
val r = height / 2
|
||||||
|
val sqrt2 = sqrt(2.0).toFloat()
|
||||||
|
// Ensure we are convex.
|
||||||
|
width = (r + sqrt2 * r).coerceAtLeast(width)
|
||||||
|
pathArcTo(mPath, r, r, r, startAngle = 90f, sweepAngle = 180f)
|
||||||
|
val o1X = width - sqrt2 * r
|
||||||
|
pathArcTo(mPath, o1X, r, r, startAngle = -90f, sweepAngle = 45f)
|
||||||
|
val r2 = r / 5
|
||||||
|
val o2X = width - sqrt2 * r2
|
||||||
|
pathArcTo(mPath, o2X, r, r2, startAngle = -45f, sweepAngle = 90f)
|
||||||
|
pathArcTo(mPath, o1X, r, r, startAngle = 45f, sweepAngle = 45f)
|
||||||
|
mPath.close()
|
||||||
|
if (shouldMirrorPath()) {
|
||||||
|
mTempMatrix.setScale(-1f, 1f, width / 2, 0f)
|
||||||
|
} else {
|
||||||
|
mTempMatrix.reset()
|
||||||
|
}
|
||||||
|
mTempMatrix.postTranslate(bounds.left.toFloat(), bounds.top.toFloat())
|
||||||
|
mPath.transform(mTempMatrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPadding(padding: Rect): Boolean {
|
||||||
|
if (shouldMirrorPath()) {
|
||||||
|
padding[mPaddingEnd, 0, mPaddingStart] = 0
|
||||||
|
} else {
|
||||||
|
padding[mPaddingStart, 0, mPaddingEnd] = 0
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOutline(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
private fun pathArcTo(
|
||||||
|
path: Path,
|
||||||
|
centerX: Float,
|
||||||
|
centerY: Float,
|
||||||
|
radius: Float,
|
||||||
|
startAngle: Float,
|
||||||
|
sweepAngle: Float
|
||||||
|
) {
|
||||||
|
path.arcTo(
|
||||||
|
centerX - radius, centerY - radius, centerX + radius, centerY + radius,
|
||||||
|
startAngle, sweepAngle, false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -118,7 +118,11 @@ public class GalleryFragment extends OCFileListFragment {
|
||||||
mAdapter.setLayoutManager(layoutManager);
|
mAdapter.setLayoutManager(layoutManager);
|
||||||
getRecyclerView().setLayoutManager(layoutManager);
|
getRecyclerView().setLayoutManager(layoutManager);
|
||||||
|
|
||||||
FastScroll.applyFastScroll(getRecyclerView(), new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter));
|
FastScroll.applyFastScroll(requireContext(),
|
||||||
|
themeColorUtils,
|
||||||
|
themeDrawableUtils,
|
||||||
|
getRecyclerView(),
|
||||||
|
new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -432,7 +432,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
||||||
|
|
||||||
setRecyclerViewAdapter(mAdapter);
|
setRecyclerViewAdapter(mAdapter);
|
||||||
|
|
||||||
FastScroll.applyFastScroll(getRecyclerView());
|
FastScroll.applyFastScroll(requireContext(), themeColorUtils, themeDrawableUtils, getRecyclerView());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void prepareCurrentSearch(SearchEvent event) {
|
protected void prepareCurrentSearch(SearchEvent event) {
|
||||||
|
|
Loading…
Reference in a new issue