Files
Radio/app/src/main/java/com/michatec/radio/helpers/UiHelper.kt
T
Michatec 669fd4683c - Release of 14.1
- Added new features
- Some bug fixes
2026-02-27 09:40:59 +01:00

269 lines
9.5 KiB
Kotlin

package com.michatec.radio.helpers
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.RectF
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.michatec.radio.Keys
import com.michatec.radio.R
/*
* UiHelper object
*/
object UiHelper {
/* Sets layout margins for given view in DP */
fun setViewMargins(
context: Context,
view: View,
left: Int = 0,
right: Int = 0,
top: Int = 0,
bottom: Int = 0
) {
val l: Int = (left * ImageHelper.getDensityScalingFactor(context)).toInt()
val r: Int = (right * ImageHelper.getDensityScalingFactor(context)).toInt()
val t: Int = (top * ImageHelper.getDensityScalingFactor(context)).toInt()
val b: Int = (bottom * ImageHelper.getDensityScalingFactor(context)).toInt()
if (view.layoutParams is ViewGroup.MarginLayoutParams) {
val p = view.layoutParams as ViewGroup.MarginLayoutParams
p.setMargins(l, t, r, b)
view.requestLayout()
}
}
/* Hide keyboard */
fun hideSoftKeyboard(context: Context, view: View) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
/*
* Inner class: Callback that detects a swipe to left
* Credit: https://github.com/kitek/android-rv-swipe-delete/blob/master/app/src/main/java/pl/kitek/rvswipetodelete/SwipeToDeleteCallback.kt
*/
abstract class SwipeToDeleteCallback(context: Context) :
ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
private val deleteIcon = ContextCompat.getDrawable(context, R.drawable.ic_remove_circle_24dp)
private val intrinsicWidth: Int = deleteIcon?.intrinsicWidth ?: 0
private val intrinsicHeight: Int = deleteIcon?.intrinsicHeight ?: 0
private val backgroundColor = ContextCompat.getColor(context, R.color.list_card_delete_background)
private val clearPaint: Paint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
private val cornerRadius: Float = dpToPx(context)
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
// disable swipe for the add new card
if (viewHolder.itemViewType == Keys.VIEW_TYPE_ADD_NEW) {
return 0
}
return super.getMovementFlags(recyclerView, viewHolder)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
// do nothing
return false
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
val itemView = viewHolder.itemView
val itemHeight = itemView.bottom - itemView.top
val isCanceled = dX == 0f && !isCurrentlyActive
if (isCanceled) {
clearCanvas(
c,
itemView.right + dX,
itemView.top.toFloat(),
itemView.right.toFloat(),
itemView.bottom.toFloat()
)
super.onChildDraw(
c,
recyclerView,
viewHolder,
dX,
dY,
actionState,
false
)
return
}
// draw delete and rounded background
val roundedBackground = RectF(
itemView.left.toFloat(),
itemView.top.toFloat(),
itemView.right.toFloat(),
itemView.bottom.toFloat()
)
val paint = Paint()
paint.color = backgroundColor
c.drawRoundRect(roundedBackground, cornerRadius, cornerRadius, paint)
// calculate position of delete icon
val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val deleteIconMargin = (itemHeight - intrinsicHeight) / 2
val deleteIconLeft = itemView.right - deleteIconMargin - intrinsicWidth
val deleteIconRight = itemView.right - deleteIconMargin
val deleteIconBottom = deleteIconTop + intrinsicHeight
// draw delete icon
deleteIcon?.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)
deleteIcon?.draw(c)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
c?.drawRect(left, top, right, bottom, clearPaint)
}
// conversion from dp to px
private fun dpToPx(context: Context): Float {
val density = context.resources.displayMetrics.density
return 24 * density
}
}
/*
* End of inner class
*/
/*
* Inner class: Callback that detects a swipe to left
* Credit: https://github.com/kitek/android-rv-swipe-delete/blob/master/app/src/main/java/pl/kitek/rvswipetodelete/SwipeToDeleteCallback.kt
*/
abstract class SwipeToMarkStarredCallback(context: Context) :
ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
private val starIcon = ContextCompat.getDrawable(context, R.drawable.ic_favorite_24dp)
private val intrinsicWidth: Int = starIcon?.intrinsicWidth ?: 0
private val intrinsicHeight: Int = starIcon?.intrinsicHeight ?: 0
private val backgroundColor = ContextCompat.getColor(context, R.color.list_card_mark_starred_background)
private val clearPaint: Paint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
private val cornerRadius: Float = dpToPx(context)
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
// disable swipe for the add new card
if (viewHolder.itemViewType == Keys.VIEW_TYPE_ADD_NEW) {
return 0
}
return super.getMovementFlags(recyclerView, viewHolder)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
// do nothing
return false
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
val itemView = viewHolder.itemView
val itemHeight = itemView.bottom - itemView.top
val isCanceled = dX == 0f && !isCurrentlyActive
if (isCanceled) {
clearCanvas(
c,
itemView.right + dX,
itemView.top.toFloat(),
itemView.right.toFloat(),
itemView.bottom.toFloat()
)
super.onChildDraw(
c,
recyclerView,
viewHolder,
dX,
dY,
actionState,
false
)
return
}
// draw favorite color and rounded background
val roundedBackground = RectF(
itemView.left.toFloat(),
itemView.top.toFloat(),
itemView.right.toFloat(),
itemView.bottom.toFloat()
)
val paint = Paint()
paint.color = backgroundColor
c.drawRoundRect(roundedBackground, cornerRadius, cornerRadius, paint)
// calculate position of delete icon
val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val deleteIconMargin = (itemHeight - intrinsicHeight) / 2
val deleteIconLeft = itemView.left + deleteIconMargin
val deleteIconRight = itemView.left + deleteIconMargin + intrinsicWidth
val deleteIconBottom = deleteIconTop + intrinsicHeight
// draw delete icon
starIcon?.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)
starIcon?.draw(c)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
private fun clearCanvas(c: Canvas?, left: Float, top: Float, right: Float, bottom: Float) {
c?.drawRect(left, top, right, bottom, clearPaint)
}
// conversion from dp to px
private fun dpToPx(context: Context): Float {
val density = context.resources.displayMetrics.density
return 24 * density
}
}
/*
* End of inner class
*/
}