|
|
|
|
@ -17,19 +17,28 @@
|
|
|
|
|
package org.koitharu.kotatsu.base.ui.widgets
|
|
|
|
|
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.content.res.ColorStateList
|
|
|
|
|
import android.graphics.drawable.Drawable
|
|
|
|
|
import android.util.AttributeSet
|
|
|
|
|
import android.view.LayoutInflater
|
|
|
|
|
import android.widget.Button
|
|
|
|
|
import android.widget.FrameLayout
|
|
|
|
|
import android.widget.TextView
|
|
|
|
|
import androidx.annotation.ColorInt
|
|
|
|
|
import androidx.annotation.StringRes
|
|
|
|
|
import androidx.core.graphics.drawable.DrawableCompat
|
|
|
|
|
import androidx.core.view.postDelayed
|
|
|
|
|
import org.koitharu.kotatsu.R
|
|
|
|
|
import com.google.android.material.color.MaterialColors
|
|
|
|
|
import com.google.android.material.shape.MaterialShapeDrawable
|
|
|
|
|
import com.google.android.material.shape.ShapeAppearanceModel
|
|
|
|
|
import com.google.android.material.snackbar.Snackbar
|
|
|
|
|
import org.koitharu.kotatsu.databinding.FadingSnackbarLayoutBinding
|
|
|
|
|
import org.koitharu.kotatsu.utils.ext.getThemeColorStateList
|
|
|
|
|
import com.google.android.material.R as materialR
|
|
|
|
|
|
|
|
|
|
private const val ENTER_DURATION = 300L
|
|
|
|
|
private const val EXIT_DURATION = 200L
|
|
|
|
|
private const val SHORT_DURATION = 1_500L
|
|
|
|
|
private const val LONG_DURATION = 2_750L
|
|
|
|
|
private const val SHORT_DURATION_MS = 1_500L
|
|
|
|
|
private const val LONG_DURATION_MS = 2_750L
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A custom snackbar implementation allowing more control over placement and entry/exit animations.
|
|
|
|
|
*
|
|
|
|
|
@ -40,16 +49,13 @@ private const val LONG_DURATION = 2_750L
|
|
|
|
|
class FadingSnackbar @JvmOverloads constructor(
|
|
|
|
|
context: Context,
|
|
|
|
|
attrs: AttributeSet? = null,
|
|
|
|
|
defStyleAttr: Int = 0
|
|
|
|
|
defStyleAttr: Int = 0,
|
|
|
|
|
) : FrameLayout(context, attrs, defStyleAttr) {
|
|
|
|
|
|
|
|
|
|
private val message: TextView
|
|
|
|
|
private val action: Button
|
|
|
|
|
private val binding = FadingSnackbarLayoutBinding.inflate(LayoutInflater.from(context), this)
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
|
val view = LayoutInflater.from(context).inflate(R.layout.fading_snackbar_layout, this, true)
|
|
|
|
|
message = view.findViewById(R.id.snackbar_text)
|
|
|
|
|
action = view.findViewById(R.id.snackbar_action)
|
|
|
|
|
binding.snackbarLayout.background = createThemedBackground()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun dismiss() {
|
|
|
|
|
@ -62,33 +68,66 @@ class FadingSnackbar @JvmOverloads constructor(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun show(
|
|
|
|
|
messageText: CharSequence? = null,
|
|
|
|
|
@StringRes actionId: Int? = null,
|
|
|
|
|
longDuration: Boolean = true,
|
|
|
|
|
actionClick: () -> Unit = { dismiss() },
|
|
|
|
|
dismissListener: () -> Unit = { }
|
|
|
|
|
messageText: CharSequence?,
|
|
|
|
|
@StringRes actionId: Int = 0,
|
|
|
|
|
duration: Int = Snackbar.LENGTH_SHORT,
|
|
|
|
|
onActionClick: (FadingSnackbar.() -> Unit)? = null,
|
|
|
|
|
onDismiss: (() -> Unit)? = null,
|
|
|
|
|
) {
|
|
|
|
|
message.text = messageText
|
|
|
|
|
if (actionId != null) {
|
|
|
|
|
action.run {
|
|
|
|
|
binding.snackbarText.text = messageText
|
|
|
|
|
if (actionId != 0) {
|
|
|
|
|
with(binding.snackbarAction) {
|
|
|
|
|
visibility = VISIBLE
|
|
|
|
|
text = context.getString(actionId)
|
|
|
|
|
setOnClickListener {
|
|
|
|
|
actionClick()
|
|
|
|
|
onActionClick?.invoke(this@FadingSnackbar) ?: dismiss()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
action.visibility = GONE
|
|
|
|
|
binding.snackbarAction.visibility = GONE
|
|
|
|
|
}
|
|
|
|
|
alpha = 0f
|
|
|
|
|
visibility = VISIBLE
|
|
|
|
|
animate()
|
|
|
|
|
.alpha(1f)
|
|
|
|
|
.duration = ENTER_DURATION
|
|
|
|
|
val showDuration = ENTER_DURATION + if (longDuration) LONG_DURATION else SHORT_DURATION
|
|
|
|
|
postDelayed(showDuration) {
|
|
|
|
|
if (duration == Snackbar.LENGTH_INDEFINITE) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
val durationMs = ENTER_DURATION + if (duration == Snackbar.LENGTH_LONG) LONG_DURATION_MS else SHORT_DURATION_MS
|
|
|
|
|
postDelayed(durationMs) {
|
|
|
|
|
dismiss()
|
|
|
|
|
dismissListener()
|
|
|
|
|
onDismiss?.invoke()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun createThemedBackground(): Drawable {
|
|
|
|
|
val backgroundColor = MaterialColors.layer(this, materialR.attr.colorSurface, materialR.attr.colorOnSurface, 1f)
|
|
|
|
|
val shapeAppearanceModel = ShapeAppearanceModel.builder(
|
|
|
|
|
context,
|
|
|
|
|
materialR.style.ShapeAppearance_Material3_Corner_ExtraSmall,
|
|
|
|
|
0
|
|
|
|
|
).build()
|
|
|
|
|
val background = createMaterialShapeDrawableBackground(
|
|
|
|
|
backgroundColor,
|
|
|
|
|
shapeAppearanceModel,
|
|
|
|
|
)
|
|
|
|
|
val backgroundTint = context.getThemeColorStateList(materialR.attr.colorSurfaceInverse)
|
|
|
|
|
return if (backgroundTint != null) {
|
|
|
|
|
val wrappedDrawable = DrawableCompat.wrap(background)
|
|
|
|
|
DrawableCompat.setTintList(wrappedDrawable, backgroundTint)
|
|
|
|
|
wrappedDrawable
|
|
|
|
|
} else {
|
|
|
|
|
DrawableCompat.wrap(background)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun createMaterialShapeDrawableBackground(
|
|
|
|
|
@ColorInt backgroundColor: Int,
|
|
|
|
|
shapeAppearanceModel: ShapeAppearanceModel,
|
|
|
|
|
): MaterialShapeDrawable {
|
|
|
|
|
val background = MaterialShapeDrawable(shapeAppearanceModel)
|
|
|
|
|
background.fillColor = ColorStateList.valueOf(backgroundColor)
|
|
|
|
|
return background
|
|
|
|
|
}
|
|
|
|
|
}
|