Remove some dead code

(cherry picked from commit b0dc20e00ce7c4cc33742fa3d4ae9d55503a25a4)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/widget/TachiyomiAppBarLayout.kt
This commit is contained in:
arkon 2022-12-02 22:48:08 -05:00 committed by Jobobby04
parent d8ba1774cb
commit bcf6904363
12 changed files with 174 additions and 616 deletions

View File

@ -270,9 +270,6 @@ dependencies {
implementation(libs.bundles.voyager)
implementation(libs.wheelpicker)
// FlowBinding
implementation(libs.flowbinding.android)
// Logging
implementation(libs.logcat)

View File

@ -37,9 +37,6 @@ import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
import exh.util.dropBlank
import exh.util.trimOrNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.clicks
@Composable
fun EditMangaDialog(
@ -190,9 +187,7 @@ private fun onViewCreated(manga: Manga, context: Context, binding: EditMangaDial
}
binding.mangaGenresTags.clearFocus()
binding.resetTags.clicks()
.onEach { resetTags(manga, binding, scope) }
.launchIn(scope)
binding.resetTags.setOnClickListener { resetTags(manga, binding, scope) }
}
private fun resetTags(manga: Manga, binding: EditMangaDialogBinding, scope: CoroutineScope) {
@ -235,7 +230,7 @@ private fun ChipGroup.setChips(items: List<String>, scope: CoroutineScope) {
setTint(context.getResourceColor(R.attr.colorAccent))
}
clicks().onEach {
setOnClickListener {
var newTag: String? = null
MaterialAlertDialogBuilder(context)
.setTitle(R.string.add_tag)
@ -247,7 +242,7 @@ private fun ChipGroup.setChips(items: List<String>, scope: CoroutineScope) {
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}.launchIn(scope)
}
}
addView(addTagChip)
}

View File

@ -16,6 +16,8 @@ import android.graphics.drawable.RippleDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.Gravity
import android.view.HapticFeedbackConstants
import android.view.KeyEvent
@ -27,8 +29,10 @@ import android.view.Window
import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.CompoundButton
import android.widget.FrameLayout
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
@ -105,20 +109,22 @@ import exh.source.isEhBasedSource
import exh.util.defaultReaderType
import exh.util.floor
import exh.util.mangaType
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.sample
import logcat.LogPriority
import nucleus.factory.RequiresPresenter
import nucleus.view.NucleusAppCompatActivity
import reactivecircus.flowbinding.android.view.clicks
import reactivecircus.flowbinding.android.widget.checkedChanges
import reactivecircus.flowbinding.android.widget.textChanges
import uy.kohesive.injekt.injectLazy
import kotlin.math.abs
import kotlin.math.max
@ -432,6 +438,36 @@ class ReaderActivity :
}
}
// SY -->
fun TextView.textChanges(): Flow<CharSequence> = callbackFlow {
val listener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
trySend(s)
}
override fun afterTextChanged(s: Editable) = Unit
}
addTextChangedListener(listener)
awaitClose { removeTextChangedListener(listener) }
}
.conflate()
.onStart { emit(text) }
fun CompoundButton.checkedChanges(): Flow<Boolean> = callbackFlow {
val listener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
trySend(isChecked)
}
setOnCheckedChangeListener(listener)
awaitClose { setOnCheckedChangeListener(null) }
}
.conflate()
.onStart { emit(isChecked) }
// SY <--
/**
* Initializes the reader menu. It sets up click listeners and the initial visibility.
*/
@ -494,30 +530,26 @@ class ReaderActivity :
// SY -->
listOf(binding.leftChapter, binding.aboveChapter).forEach {
it.clicks()
.onEach {
if (viewer != null) {
if (viewer is R2LPagerViewer) {
loadNextChapter()
} else {
loadPreviousChapter()
}
it.setOnClickListener {
if (viewer != null) {
if (viewer is R2LPagerViewer) {
loadNextChapter()
} else {
loadPreviousChapter()
}
}
.launchIn(lifecycleScope)
}
}
listOf(binding.rightChapter, binding.belowChapter).forEach {
it.clicks()
.onEach {
if (viewer != null) {
if (viewer is R2LPagerViewer) {
loadPreviousChapter()
} else {
loadNextChapter()
}
it.setOnClickListener {
if (viewer != null) {
if (viewer is R2LPagerViewer) {
loadPreviousChapter()
} else {
loadNextChapter()
}
}
.launchIn(lifecycleScope)
}
}
initBottomShortcuts()
@ -713,12 +745,10 @@ class ReaderActivity :
}
fun initDropdownMenu() {
binding.expandEhButton.clicks()
.onEach {
ehUtilsVisible = !ehUtilsVisible
setEhUtilsVisibility(ehUtilsVisible)
}
.launchIn(lifecycleScope)
binding.expandEhButton.setOnClickListener {
ehUtilsVisible = !ehUtilsVisible
setEhUtilsVisibility(ehUtilsVisible)
}
binding.ehAutoscrollFreq.setText(
readerPreferences.autoscrollInterval().get().let {
@ -763,105 +793,95 @@ class ReaderActivity :
}
.launchIn(lifecycleScope)
binding.ehAutoscrollHelp.clicks()
.onEach {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_autoscroll_help)
.setMessage(R.string.eh_autoscroll_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
.launchIn(lifecycleScope)
binding.ehAutoscrollHelp.setOnClickListener {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_autoscroll_help)
.setMessage(R.string.eh_autoscroll_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
binding.ehRetryAll.clicks()
.onEach {
var retried = 0
binding.ehRetryAll.setOnClickListener {
var retried = 0
presenter.viewerChaptersRelay.value
.currChapter
.pages
?.forEachIndexed { _, page ->
var shouldQueuePage = false
if (page.status == Page.ERROR) {
shouldQueuePage = true
} /*else if (page.status == Page.LOAD_PAGE ||
page.status == Page.DOWNLOAD_IMAGE) {
// Do nothing
}*/
presenter.viewerChaptersRelay.value
.currChapter
.pages
?.forEachIndexed { _, page ->
var shouldQueuePage = false
if (page.status == Page.ERROR) {
shouldQueuePage = true
} /*else if (page.status == Page.LOAD_PAGE ||
page.status == Page.DOWNLOAD_IMAGE) {
// Do nothing
}*/
if (shouldQueuePage) {
page.status = Page.QUEUE
} else {
return@forEachIndexed
}
// If we are using EHentai/ExHentai, get a new image URL
presenter.manga?.let { m ->
val src = sourceManager.get(m.source)
if (src?.isEhBasedSource() == true) {
page.imageUrl = null
}
}
val loader = page.chapter.pageLoader
if (page.index == exhCurrentpage()?.index && loader is HttpPageLoader) {
loader.boostPage(page)
} else {
loader?.retryPage(page)
}
retried++
}
toast(resources.getQuantityString(R.plurals.eh_retry_toast, retried, retried))
}
.launchIn(lifecycleScope)
binding.ehRetryAllHelp.clicks()
.onEach {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_retry_all_help)
.setMessage(R.string.eh_retry_all_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
.launchIn(lifecycleScope)
binding.ehBoostPage.clicks()
.onEach {
viewer ?: return@onEach
val curPage = exhCurrentpage() ?: run {
toast(R.string.eh_boost_page_invalid)
return@onEach
}
if (curPage.status == Page.ERROR) {
toast(R.string.eh_boost_page_errored)
} else if (curPage.status == Page.LOAD_PAGE || curPage.status == Page.DOWNLOAD_IMAGE) {
toast(R.string.eh_boost_page_downloading)
} else if (curPage.status == Page.READY) {
toast(R.string.eh_boost_page_downloaded)
} else {
val loader = (presenter.viewerChaptersRelay.value.currChapter.pageLoader as? HttpPageLoader)
if (loader != null) {
loader.boostPage(curPage)
toast(R.string.eh_boost_boosted)
if (shouldQueuePage) {
page.status = Page.QUEUE
} else {
toast(R.string.eh_boost_invalid_loader)
return@forEachIndexed
}
// If we are using EHentai/ExHentai, get a new image URL
presenter.manga?.let { m ->
val src = sourceManager.get(m.source)
if (src?.isEhBasedSource() == true) {
page.imageUrl = null
}
}
val loader = page.chapter.pageLoader
if (page.index == exhCurrentpage()?.index && loader is HttpPageLoader) {
loader.boostPage(page)
} else {
loader?.retryPage(page)
}
retried++
}
toast(resources.getQuantityString(R.plurals.eh_retry_toast, retried, retried))
}
binding.ehRetryAllHelp.setOnClickListener {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_retry_all_help)
.setMessage(R.string.eh_retry_all_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
binding.ehBoostPage.setOnClickListener {
viewer ?: return@setOnClickListener
val curPage = exhCurrentpage() ?: run {
toast(R.string.eh_boost_page_invalid)
return@setOnClickListener
}
if (curPage.status == Page.ERROR) {
toast(R.string.eh_boost_page_errored)
} else if (curPage.status == Page.LOAD_PAGE || curPage.status == Page.DOWNLOAD_IMAGE) {
toast(R.string.eh_boost_page_downloading)
} else if (curPage.status == Page.READY) {
toast(R.string.eh_boost_page_downloaded)
} else {
val loader = (presenter.viewerChaptersRelay.value.currChapter.pageLoader as? HttpPageLoader)
if (loader != null) {
loader.boostPage(curPage)
toast(R.string.eh_boost_boosted)
} else {
toast(R.string.eh_boost_invalid_loader)
}
}
.launchIn(lifecycleScope)
}
binding.ehBoostPageHelp.clicks()
.onEach {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_boost_page_help)
.setMessage(R.string.eh_boost_page_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
.launchIn(lifecycleScope)
binding.ehBoostPageHelp.setOnClickListener {
MaterialAlertDialogBuilder(this)
.setTitle(R.string.eh_boost_page_help)
.setMessage(R.string.eh_boost_page_help_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
private fun exhCurrentpage(): ReaderPage? {

View File

@ -1,8 +1,6 @@
package eu.kanade.tachiyomi.util.system
import android.app.ActivityManager
import android.app.KeyguardManager
import android.app.Notification
import android.app.NotificationManager
import android.content.ClipData
import android.content.ClipboardManager
@ -24,11 +22,9 @@ import android.util.TypedValue
import android.view.Display
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.graphics.alpha
@ -75,34 +71,6 @@ fun Context.copyToClipboard(label: String, content: String) {
}
}
/**
* Helper method to create a notification builder.
*
* @param id the channel id.
* @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated.
*/
fun Context.notificationBuilder(channelId: String, block: (NotificationCompat.Builder.() -> Unit)? = null): NotificationCompat.Builder {
val builder = NotificationCompat.Builder(this, channelId)
.setColor(getColor(R.color.accent_blue))
if (block != null) {
builder.block()
}
return builder
}
/**
* Helper method to create a notification.
*
* @param id the channel id.
* @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated.
*/
fun Context.notification(channelId: String, block: (NotificationCompat.Builder.() -> Unit)?): Notification {
val builder = notificationBuilder(channelId, block)
return builder.build()
}
/**
* Checks if the give permission is granted.
*
@ -146,12 +114,6 @@ fun Context.hasPermission(permission: String) = ContextCompat.checkSelfPermissio
val getDisplayMaxHeightInPx: Int
get() = Resources.getSystem().displayMetrics.let { max(it.heightPixels, it.widthPixels) }
/**
* Converts to dp.
*/
val Int.pxToDp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
/**
* Converts to px.
*/
@ -182,12 +144,6 @@ val Context.wifiManager: WifiManager
val Context.powerManager: PowerManager
get() = getSystemService()!!
val Context.keyguardManager: KeyguardManager
get() = getSystemService()!!
val Context.inputMethodManager: InputMethodManager
get() = getSystemService()!!
val Context.displayCompat: Display?
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
display

View File

@ -1,7 +1,11 @@
package eu.kanade.tachiyomi.util.system
import android.app.Notification
import android.content.Context
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationChannelGroupCompat
import androidx.core.app.NotificationCompat
import eu.kanade.tachiyomi.R
/**
* Helper method to build a notification channel group.
@ -36,3 +40,31 @@ fun buildNotificationChannel(
builder.block()
return builder.build()
}
/**
* Helper method to create a notification builder.
*
* @param id the channel id.
* @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated.
*/
fun Context.notificationBuilder(channelId: String, block: (NotificationCompat.Builder.() -> Unit)? = null): NotificationCompat.Builder {
val builder = NotificationCompat.Builder(this, channelId)
.setColor(getColor(R.color.accent_blue))
if (block != null) {
builder.block()
}
return builder
}
/**
* Helper method to create a notification.
*
* @param id the channel id.
* @param block the function that will execute inside the builder.
* @return a notification to be displayed or updated.
*/
fun Context.notification(channelId: String, block: (NotificationCompat.Builder.() -> Unit)?): Notification {
val builder = notificationBuilder(channelId, block)
return builder.build()
}

View File

@ -1,19 +1,9 @@
package eu.kanade.tachiyomi.util.view
import android.content.Context
import android.graphics.drawable.Animatable
import android.graphics.drawable.ColorDrawable
import android.widget.ImageView
import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import coil.ImageLoader
import coil.imageLoader
import coil.load
import coil.request.ImageRequest
import coil.target.ImageViewTarget
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.animatorDurationScale
import eu.kanade.tachiyomi.util.system.getResourceColor
/**
@ -29,33 +19,3 @@ fun ImageView.setVectorCompat(@DrawableRes drawable: Int, @AttrRes tint: Int? =
}
setImageDrawable(vector)
}
/**
* Load the image referenced by [data] and set it on this [ImageView],
* and if the image is animated, this will also disable that animation
* if [Context.animatorDurationScale] is 0
*/
fun ImageView.loadAutoPause(
data: Any?,
loader: ImageLoader = context.imageLoader,
builder: ImageRequest.Builder.() -> Unit = {},
) {
load(data, loader) {
placeholder(ColorDrawable(context.getColor(R.color.cover_placeholder)))
error(R.drawable.cover_error)
// Build the original request so we can add on our success listener
val originalListener = apply(builder).build().listener
listener(
onSuccess = { request, metadata ->
(request.target as? ImageViewTarget)?.drawable.let {
if (it is Animatable && context.animatorDurationScale == 0f) it.stop()
}
originalListener?.onSuccess(request, metadata)
},
onStart = { request -> originalListener?.onStart(request) },
onCancel = { request -> originalListener?.onCancel(request) },
onError = { request, throwable -> originalListener?.onError(request, throwable) },
)
}
}

View File

@ -11,7 +11,6 @@ import android.view.Gravity
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.MenuRes
@ -29,15 +28,11 @@ import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.view.children
import androidx.core.view.descendants
import androidx.core.view.forEach
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.inputMethodManager
inline fun ComposeView.setComposeContent(crossinline content: @Composable () -> Unit) {
consumeWindowInsets = false
@ -70,24 +65,6 @@ inline fun ComponentActivity.setComposeContent(
}
}
/**
* Shows a snackbar in this view.
*
* @param message the message to show.
* @param length the duration of the snack.
* @param f a function to execute in the snack, allowing for example to define a custom action.
*/
inline fun View.snack(
message: String,
length: Int = 10_000,
f: Snackbar.() -> Unit = {},
): Snackbar {
val snack = Snackbar.make(this, message, length)
snack.f()
snack.show()
return snack
}
/**
* Adds a tooltip shown on long press.
*
@ -173,20 +150,6 @@ inline fun View.popupMenu(
return popup
}
/**
* Returns this ViewGroup's first child of specified class
*/
inline fun <reified T> ViewGroup.findChild(): T? {
return children.find { it is T } as? T
}
/**
* Returns this ViewGroup's first descendant of specified class
*/
inline fun <reified T> ViewGroup.findDescendant(): T? {
return descendants.find { it is T } as? T
}
/**
* Returns a deep copy of the provided [Drawable]
*/
@ -210,7 +173,3 @@ fun View?.isVisibleOnScreen(): Boolean {
val screen = Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels)
return actualPosition.intersect(screen)
}
fun View.hideKeyboard() {
context.inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
}

View File

@ -1,214 +0,0 @@
@file:Suppress("PackageDirectoryMismatch")
package com.google.android.material.appbar
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.animation.LinearInterpolator
import android.widget.TextView
import androidx.annotation.FloatRange
import androidx.core.graphics.withTranslation
import androidx.lifecycle.coroutineScope
import androidx.lifecycle.findViewTreeLifecycleOwner
import com.google.android.material.shape.MaterialShapeDrawable
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.view.findChild
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.view.HierarchyChangeEvent
import reactivecircus.flowbinding.android.view.hierarchyChangeEvents
/**
* [AppBarLayout] with our own lift state handler and custom title alpha.
*
* Inside this package to access some package-private methods.
*/
class TachiyomiAppBarLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : AppBarLayout(context, attrs) {
private var lifted = true
private val toolbar by lazy { findViewById<MaterialToolbar>(R.id.toolbar) }
@FloatRange(from = 0.0, to = 1.0)
var titleTextAlpha = 1F
set(value) {
field = value
titleTextView?.alpha = field
}
private var titleTextView: TextView? = null
set(value) {
field = value
field?.alpha = titleTextAlpha
}
private var animatorSet: AnimatorSet? = null
private var statusBarForegroundAnimator: ValueAnimator? = null
private var currentOffset = 0
var isTransparentWhenNotLifted = false
set(value) {
if (field != value) {
field = value
updateStates()
}
}
/**
* Disabled. Lift on scroll is handled manually with [eu.kanade.tachiyomi.widget.TachiyomiCoordinatorLayout]
*/
override fun isLiftOnScroll(): Boolean = false
override fun isLifted(): Boolean = lifted
override fun setLifted(lifted: Boolean): Boolean {
return if (this.lifted != lifted) {
this.lifted = lifted
updateStates()
true
} else {
false
}
}
override fun setLiftedState(lifted: Boolean, force: Boolean): Boolean = false
override fun draw(canvas: Canvas) {
super.draw(canvas)
canvas.withTranslation(y = -currentOffset.toFloat()) {
statusBarForeground?.draw(this)
}
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
statusBarForeground?.setBounds(0, 0, width, paddingTop)
}
override fun onOffsetChanged(offset: Int) {
currentOffset = offset
super.onOffsetChanged(offset)
// Show status bar foreground when offset
val foreground = (statusBarForeground as? MaterialShapeDrawable) ?: return
val start = foreground.alpha
val end = if (offset != 0) 255 else 0
statusBarForegroundAnimator?.cancel()
if (animatorSet?.isRunning == true) {
foreground.alpha = end
return
}
if (start != end) {
statusBarForegroundAnimator = ValueAnimator.ofInt(start, end).apply {
duration = resources.getInteger(R.integer.app_bar_elevation_anim_duration).toLong()
interpolator = LINEAR_INTERPOLATOR
addUpdateListener {
foreground.alpha = it.animatedValue as Int
}
start()
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
toolbar.background.alpha = 0 // Use app bar background
titleTextView = toolbar.findChild<TextView>()
findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.let { scope ->
toolbar.hierarchyChangeEvents()
.onEach {
when (it) {
is HierarchyChangeEvent.ChildAdded -> {
if (it.child is TextView) {
titleTextView = it.child as TextView
}
}
is HierarchyChangeEvent.ChildRemoved -> {
if (it.child == titleTextView) {
titleTextView = null
}
}
}
}
.launchIn(scope)
}
}
override fun setStatusBarForeground(drawable: Drawable?) {
super.setStatusBarForeground(drawable)
setWillNotDraw(statusBarForeground == null)
}
@SuppressLint("Recycle")
private fun updateStates() {
val animators = mutableListOf<ValueAnimator>()
val fromElevation = elevation
val toElevation = if (lifted) {
resources.getDimension(R.dimen.design_appbar_elevation)
} else {
0F
}
if (fromElevation != toElevation) {
ValueAnimator.ofFloat(fromElevation, toElevation).apply {
addUpdateListener {
elevation = it.animatedValue as Float
(statusBarForeground as? MaterialShapeDrawable)?.elevation = it.animatedValue as Float
}
animators.add(this)
}
}
val transparent = if (lifted) false else isTransparentWhenNotLifted
val fromAlpha = (background as? MaterialShapeDrawable)?.alpha ?: background.alpha
val toAlpha = if (transparent) 0 else 255
if (fromAlpha != toAlpha) {
ValueAnimator.ofInt(fromAlpha, toAlpha).apply {
addUpdateListener {
val value = it.animatedValue as Int
background.alpha = value
}
animators.add(this)
}
}
if (animators.isNotEmpty()) {
animatorSet?.cancel()
animatorSet = AnimatorSet().apply {
duration = resources.getInteger(R.integer.app_bar_elevation_anim_duration).toLong()
interpolator = LINEAR_INTERPOLATOR
playTogether(*animators.toTypedArray())
start()
}
}
}
init {
statusBarForeground = MaterialShapeDrawable.createWithElevationOverlay(context)
applyInsetter {
type(navigationBars = true) {
margin(horizontal = true)
}
type(statusBars = true) {
padding(top = true)
}
ignoreVisibility(true)
}
}
companion object {
private val LINEAR_INTERPOLATOR = LinearInterpolator()
}
}

View File

@ -1,130 +0,0 @@
package eu.kanade.tachiyomi.widget
import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import androidx.compose.ui.platform.ComposeView
import androidx.coordinatorlayout.R
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.ViewCompat
import androidx.core.view.doOnLayout
import androidx.core.view.isVisible
import androidx.customview.view.AbsSavedState
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayout
import eu.kanade.tachiyomi.util.system.isTabletUi
import eu.kanade.tachiyomi.util.view.findChild
/**
* [CoordinatorLayout] with its own app bar lift state handler.
* This parent view checks for the app bar lift state from the following:
*
* 1. When nested scroll detected, lift state will be decided from the nested
* scroll target. (See [onNestedScroll])
*
* With those conditions, this view expects the following direct child:
*
* 1. An [AppBarLayout].
*/
class TachiyomiCoordinatorLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.coordinatorLayoutStyle,
) : CoordinatorLayout(context, attrs, defStyleAttr) {
private var appBarLayout: AppBarLayout? = null
private var tabLayout: TabLayout? = null
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int,
consumed: IntArray,
) {
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type, consumed)
// Disable elevation overlay when tabs are visible
if (context.isTabletUi().not()) {
if (target is ComposeView) {
val scrollCondition = if (type == ViewCompat.TYPE_NON_TOUCH) {
dyUnconsumed >= 0
} else {
dyConsumed != 0 || dyUnconsumed >= 0
}
appBarLayout?.isLifted = scrollCondition && tabLayout?.isVisible == false
} else {
appBarLayout?.isLifted = (dyConsumed != 0 || dyUnconsumed >= 0) && tabLayout?.isVisible == false
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
appBarLayout = findChild()
tabLayout = appBarLayout?.findChild()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
appBarLayout = null
tabLayout = null
}
override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
return if (superState != null) {
SavedState(superState).also {
it.appBarLifted = appBarLayout?.isLifted ?: false
}
} else {
superState
}
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state is SavedState) {
super.onRestoreInstanceState(state.superState)
doOnLayout {
appBarLayout?.isLifted = state.appBarLifted
}
} else {
super.onRestoreInstanceState(state)
}
}
internal class SavedState : AbsSavedState {
var appBarLifted = false
constructor(superState: Parcelable) : super(superState)
constructor(source: Parcel, loader: ClassLoader?) : super(source, loader) {
appBarLifted = source.readByte().toInt() == 1
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeByte((if (appBarLifted) 1 else 0).toByte())
}
companion object {
@JvmField
val CREATOR: Parcelable.ClassLoaderCreator<SavedState> = object : Parcelable.ClassLoaderCreator<SavedState> {
override fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState {
return SavedState(source, loader)
}
override fun createFromParcel(source: Parcel): SavedState {
return SavedState(source, null)
}
override fun newArray(size: Int): Array<SavedState> {
return newArray(size)
}
}
}
}
}

View File

@ -1,15 +0,0 @@
package eu.kanade.tachiyomi.widget
import com.google.android.material.appbar.AppBarLayout
/**
* [AppBarLayout.ScrollingViewBehavior] that lets the app bar overlaps the scrolling child.
*/
class TachiyomiScrollingViewBehavior : AppBarLayout.ScrollingViewBehavior() {
var shouldHeaderOverlap = false
override fun shouldHeaderOverlapScrollingChild(): Boolean {
return shouldHeaderOverlap
}
}

View File

@ -39,4 +39,4 @@ workmanager = ["work-runtime", "guava"]
[plugins]
application = { id = "com.android.application", version.ref = "agp_version" }
library = { id = "com.android.library", version.ref = "agp_version" }
test = { id = "com.android.test", version.ref = "agp_version"}
test = { id = "com.android.test", version.ref = "agp_version" }

View File

@ -65,8 +65,6 @@ insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
cascade = "me.saket.cascade:cascade-compose:2.0.0-beta1"
wheelpicker = "com.github.commandiron:WheelPickerCompose:1.0.11"
flowbinding-android = "io.github.reactivecircus.flowbinding:flowbinding-android:1.2.0"
logcat = "com.squareup.logcat:logcat:0.1"
acra-http = "ch.acra:acra-http:5.9.7"