EmptyScreen: Compose-ify and apply content padding (#8177)

* Apply content padding to empty screen

except the empty screens in browse

* compose-ify EmptyScreen

* center face when action show

* fix padding

* apply content padding to browse tabs

* fix duplicate bottom insets
This commit is contained in:
Ivan Iskandar
2022-10-10 02:52:56 +07:00
committed by GitHub
parent 23bfa1f18f
commit 8500add09f
27 changed files with 413 additions and 239 deletions

View File

@@ -1,26 +1,24 @@
package eu.kanade.tachiyomi.widget
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.view.ContextThemeWrapper
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.AbstractComposeView
import androidx.core.view.isVisible
import com.google.android.material.button.MaterialButton
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.CommonViewEmptyBinding
import eu.kanade.tachiyomi.util.system.getThemeColor
import kotlin.random.Random
import eu.kanade.presentation.components.EmptyScreen
import eu.kanade.presentation.theme.TachiyomiTheme
class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
RelativeLayout(context, attrs) {
AbstractComposeView(context, attrs) {
private val binding: CommonViewEmptyBinding =
CommonViewEmptyBinding.inflate(LayoutInflater.from(context), this, true)
var message by mutableStateOf("")
/**
* Hide the information view
@@ -33,62 +31,17 @@ class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
* Show the information view
* @param textResource text of information view
*/
fun show(@StringRes textResource: Int, actions: List<Action>? = null) {
show(context.getString(textResource), actions)
}
fun show(message: String, actions: List<Action>? = null) {
binding.textFace.text = getRandomErrorFace()
binding.textLabel.text = message
binding.actionsContainer.removeAllViews()
val buttonContext = ContextThemeWrapper(context, R.style.Widget_Tachiyomi_Button_ActionButton)
val buttonColor = ColorStateList.valueOf(context.getThemeColor(R.attr.colorOnBackground))
actions?.forEach {
val button = MaterialButton(
buttonContext,
null,
R.attr.borderlessButtonStyle,
).apply {
layoutParams = LinearLayout.LayoutParams(
0,
LinearLayout.LayoutParams.WRAP_CONTENT,
1f / actions.size,
)
setTextColor(buttonColor)
iconTint = buttonColor
setIconResource(it.iconResId)
setText(it.stringResId)
setOnClickListener(it.listener)
}
binding.actionsContainer.addView(button)
}
fun show(@StringRes textResource: Int) {
message = context.getString(textResource)
this.isVisible = true
}
companion object {
private val ERROR_FACES = listOf(
"(・o・;)",
"Σ(ಠ_ಠ)",
"ಥ_ಥ",
"(˘・_・˘)",
"(; ̄Д ̄)",
"(・Д・。",
)
fun getRandomErrorFace(): String {
return ERROR_FACES[Random.nextInt(ERROR_FACES.size)]
@Composable
override fun Content() {
TachiyomiTheme {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
EmptyScreen(message = message)
}
}
}
data class Action(
@StringRes val stringResId: Int,
@DrawableRes val iconResId: Int,
val listener: OnClickListener,
)
}

View File

@@ -9,10 +9,16 @@ import android.os.Parcelable
import android.util.AttributeSet
import android.view.ViewPropertyAnimator
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.customview.view.AbsSavedState
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
@@ -58,7 +64,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
bottomNavPadding = PaddingValues(bottom = h.pxToDp.dp)
bottomNavPadding = h.pxToDp.dp
}
/**
@@ -74,6 +80,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
SLIDE_UP_ANIMATION_DURATION,
LinearOutSlowInInterpolator(),
)
bottomNavPadding = height.pxToDp.dp
}
/**
@@ -89,6 +96,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
SLIDE_DOWN_ANIMATION_DURATION,
FastOutLinearInInterpolator(),
)
bottomNavPadding = 0.dp
}
private fun animateTranslation(targetY: Float, duration: Long, interpolator: TimeInterpolator) {
@@ -149,7 +157,21 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
private const val SLIDE_UP_ANIMATION_DURATION = 225L
private const val SLIDE_DOWN_ANIMATION_DURATION = 175L
var bottomNavPadding by mutableStateOf(PaddingValues())
private set
private var bottomNavPadding by mutableStateOf(0.dp)
/**
* Merges [bottomNavPadding] to the origin's [PaddingValues] bottom side.
*/
@ReadOnlyComposable
@Composable
fun withBottomNavPadding(origin: PaddingValues = PaddingValues()): PaddingValues {
val layoutDirection = LocalLayoutDirection.current
return PaddingValues(
start = origin.calculateStartPadding(layoutDirection),
top = origin.calculateTopPadding(),
end = origin.calculateEndPadding(layoutDirection),
bottom = max(origin.calculateBottomPadding(), bottomNavPadding),
)
}
}
}