mirror of
https://github.com/nextcloud/android.git
synced 2024-11-24 06:05:42 +03:00
Merge pull request #10396 from nextcloud/fix/scrollbar-theming
Make fast scroll bar and popup use the theme color
This commit is contained in:
commit
82d86b978b
4 changed files with 208 additions and 4 deletions
|
@ -27,23 +27,59 @@
|
|||
|
||||
package com.nextcloud.utils.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.FastScrollerBuilder
|
||||
import me.zhanghai.android.fastscroll.PopupStyles
|
||||
|
||||
object FastScroll {
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun applyFastScroll(recyclerView: RecyclerView, viewHelper: FastScroller.ViewHelper? = null) {
|
||||
val builder = FastScrollerBuilder(recyclerView).useMd2Style()
|
||||
fun applyFastScroll(
|
||||
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) {
|
||||
builder.setViewHelper(viewHelper)
|
||||
}
|
||||
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
|
||||
fun fixAppBarForFastScroll(appBarLayout: AppBarLayout, content: ViewGroup) {
|
||||
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);
|
||||
getRecyclerView().setLayoutManager(layoutManager);
|
||||
|
||||
FastScroll.applyFastScroll(getRecyclerView(), new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter));
|
||||
FastScroll.applyFastScroll(requireContext(),
|
||||
themeColorUtils,
|
||||
themeDrawableUtils,
|
||||
getRecyclerView(),
|
||||
new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -432,7 +432,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
|
||||
setRecyclerViewAdapter(mAdapter);
|
||||
|
||||
FastScroll.applyFastScroll(getRecyclerView());
|
||||
FastScroll.applyFastScroll(requireContext(), themeColorUtils, themeDrawableUtils, getRecyclerView());
|
||||
}
|
||||
|
||||
protected void prepareCurrentSearch(SearchEvent event) {
|
||||
|
|
Loading…
Reference in a new issue