Search bar toolbar in some screens + many search fixes

This would be a yoink if this wasn't from scratch, so let's call it a spiritual yoink

Floating search bar as a toolbar for the following screens:
Library, Recents, Browse, Settings, Browse Source, Global search

Fixes include:
Searching now saves when pausing/resuming tachi activity

Other changes:
Tapping on the search bar in library also shows backdrop now (which will collapse on close/starting to type
Also using a subtitle in the library to show the current category

*good luck TF*
This commit is contained in:
Jays2Kings 2021-04-24 14:52:05 -04:00
parent 9d74c2fba3
commit 2d520026a1
28 changed files with 666 additions and 216 deletions

View File

@ -0,0 +1,93 @@
package eu.kanade.tachiyomi.ui.base
import android.content.Context
import android.util.AttributeSet
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.core.view.isVisible
import com.google.android.material.appbar.MaterialToolbar
import eu.kanade.tachiyomi.R
open class BaseToolbar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
MaterialToolbar(context, attrs) {
protected lateinit var toolbarTitle: TextView
private val defStyleRes = com.google.android.material.R.style.Widget_MaterialComponents_Toolbar
protected val titleTextAppeance: Int
var incognito = false
var hasDropdown: Boolean? = null
init {
val a = context.obtainStyledAttributes(
attrs,
R.styleable.Toolbar,
0,
defStyleRes
)
titleTextAppeance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0)
a.recycle()
}
override fun setTitle(resId: Int) {
setCustomTitle(context.getString(resId))
}
override fun setTitle(title: CharSequence?) {
setCustomTitle(title)
}
protected open fun setCustomTitle(title: CharSequence?) {
toolbarTitle.isVisible = true
toolbarTitle.text = title
super.setTitle(null)
if (navigationIcon is DrawerArrowDrawable) {
hideDropdown()
}
setIncognitoMode(incognito)
}
fun hideDropdown() {
hasDropdown = null
setIcons()
}
fun showDropdown(down: Boolean = true) {
hasDropdown = down
setIcons()
}
fun setIncognitoMode(enabled: Boolean) {
incognito = enabled
setIcons()
}
open fun setIcons() {
toolbarTitle.setCompoundDrawablesRelativeWithIntrinsicBounds(
getIncogRes(),
0,
getDropdownRes(),
0
)
}
@DrawableRes
private fun getIncogRes(): Int {
return when {
incognito -> R.drawable.ic_incognito_circle_24dp
hasDropdown != null -> R.drawable.ic_blank_24dp
else -> 0
}
}
@DrawableRes
private fun getDropdownRes(): Int {
return when {
hasDropdown == true -> R.drawable.ic_arrow_drop_down_24dp
hasDropdown == false -> R.drawable.ic_arrow_drop_up_24dp
incognito && navigationIcon !is DrawerArrowDrawable -> R.drawable.ic_blank_28dp
else -> 0
}
}
}

View File

@ -4,12 +4,8 @@ import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.textview.MaterialTextView
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.dpToPx
@ -17,25 +13,8 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
@SuppressLint("CustomViewStyleable")
class CenteredToolbar@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
MaterialToolbar(context, attrs) {
BaseToolbar(context, attrs) {
private lateinit var toolbarTitle: TextView
private val defStyleRes = com.google.android.material.R.style.Widget_MaterialComponents_Toolbar
private val titleTextAppeance: Int
var incognito = false
var hasDropdown: Boolean? = null
init {
val a = context.obtainStyledAttributes(
attrs,
R.styleable.Toolbar,
0,
defStyleRes
)
titleTextAppeance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0)
a.recycle()
}
override fun onFinishInflate() {
super.onFinishInflate()
toolbarTitle = findViewById<MaterialTextView>(R.id.toolbar_title)
@ -43,68 +22,11 @@ class CenteredToolbar@JvmOverloads constructor(context: Context, attrs: Attribut
toolbarTitle.setTextColor(context.getResourceColor(R.attr.actionBarTintColor))
}
override fun setTitle(resId: Int) {
setCustomTitle(context.getString(resId))
}
override fun setTitle(title: CharSequence?) {
setCustomTitle(title)
}
private fun setCustomTitle(title: CharSequence?) {
toolbarTitle.isVisible = true
toolbarTitle.text = title
super.setTitle(null)
override fun setCustomTitle(title: CharSequence?) {
super.setCustomTitle(title)
toolbarTitle.updateLayoutParams<LayoutParams> {
gravity = if (navigationIcon is DrawerArrowDrawable) Gravity.START else Gravity.CENTER
}
toolbarTitle.compoundDrawablePadding = if (navigationIcon is DrawerArrowDrawable) 6.dpToPx else 0
if (navigationIcon is DrawerArrowDrawable) {
hideDropdown()
}
setIncognitoMode(incognito)
}
fun hideDropdown() {
hasDropdown = null
setIcons()
}
fun showDropdown(down: Boolean = true) {
hasDropdown = down
setIcons()
}
fun setIncognitoMode(enabled: Boolean) {
incognito = enabled
setIcons()
}
private fun setIcons() {
toolbarTitle.setCompoundDrawablesRelativeWithIntrinsicBounds(
getIncogRes(),
0,
getDropdownRes(),
0
)
}
@DrawableRes
private fun getIncogRes(): Int {
return when {
incognito -> R.drawable.ic_incognito_circle_24dp
hasDropdown != null -> R.drawable.ic_blank_24dp
else -> 0
}
}
@DrawableRes
private fun getDropdownRes(): Int {
return when {
hasDropdown == true -> R.drawable.ic_arrow_drop_down_24dp
hasDropdown == false -> R.drawable.ic_arrow_drop_up_24dp
incognito && navigationIcon !is DrawerArrowDrawable -> R.drawable.ic_blank_28dp
else -> 0
}
}
}

View File

@ -0,0 +1,77 @@
package eu.kanade.tachiyomi.ui.base
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import com.google.android.material.textview.MaterialTextView
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getResourceColor
class FloatingToolbar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
BaseToolbar(context, attrs) {
private val actionColorAlpha = ColorUtils.setAlphaComponent(context.getResourceColor(R.attr.actionBarTintColor), 200)
private val actionColorAlphaSecondary = ColorUtils.setAlphaComponent(context.getResourceColor(R.attr.actionBarTintColor), 150)
private lateinit var toolbarsubTitle: TextView
private lateinit var cardIncogImage: ImageView
private val defStyleRes = com.google.android.material.R.style.Widget_MaterialComponents_Toolbar
private val subtitleTextAppeance: Int
init {
val a = context.obtainStyledAttributes(
attrs,
R.styleable.Toolbar,
0,
defStyleRes
)
subtitleTextAppeance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0)
a.recycle()
}
override fun onFinishInflate() {
super.onFinishInflate()
toolbarTitle = findViewById<MaterialTextView>(R.id.card_title)
toolbarTitle.setTextAppearance(titleTextAppeance)
toolbarTitle.setTextColor(actionColorAlpha)
toolbarsubTitle = findViewById<MaterialTextView>(R.id.card_subtitle)
toolbarsubTitle.setTextAppearance(subtitleTextAppeance)
toolbarsubTitle.setTextColor(actionColorAlphaSecondary)
toolbarsubTitle.isVisible = false
cardIncogImage = findViewById(R.id.card_incog_image)
setNavigationIconTint(actionColorAlpha)
}
override fun setSubtitle(resId: Int) {
setCustomSubtitle(context.getString(resId))
}
override fun setSubtitle(subtitle: CharSequence?) {
setCustomSubtitle(subtitle)
}
override fun setIcons() {
cardIncogImage.isVisible = incognito
}
private fun setCustomSubtitle(title: CharSequence?) {
toolbarsubTitle.isVisible = !title.isNullOrBlank()
toolbarsubTitle.text = title
super.setSubtitle(null)
}
override fun setCustomTitle(title: CharSequence?) {
super.setCustomTitle(title)
toolbarTitle.updateLayoutParams<LinearLayout.LayoutParams> {
gravity = Gravity.START
}
}
}

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.ui.base
import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import androidx.appcompat.widget.SearchView
import androidx.core.graphics.ColorUtils
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getResourceColor
class MiniSearchView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
SearchView(context, attrs) {
init {
val searchTextView =
findViewById<SearchAutoComplete>(androidx.appcompat.R.id.search_src_text)
searchTextView?.setTextAppearance(android.R.style.TextAppearance_Material_Body1)
val actionColorAlpha =
ColorUtils.setAlphaComponent(context.getResourceColor(R.attr.actionBarTintColor), 200)
searchTextView?.setTextColor(actionColorAlpha)
searchTextView?.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16f)
searchTextView?.setHintTextColor(actionColorAlpha)
}
}

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.base.controller
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
@ -11,6 +12,7 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RestoreViewOnCreateController
import eu.kanade.tachiyomi.util.view.removeQueryListener
import timber.log.Timber
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
@ -57,6 +59,8 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
if (type.isEnter) {
setTitle()
} else {
removeQueryListener()
}
setHasOptionsMenu(type.isEnter)
super.onChangeStarted(handler, type)
@ -69,6 +73,11 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
return null
}
override fun onActivityPaused(activity: Activity) {
super.onActivityPaused(activity)
removeQueryListener()
}
fun setTitle() {
var parentController = parentController
while (parentController != null) {
@ -114,6 +123,10 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
}
}
fun MenuItem.fixExpandInvalidate() {
fixExpand { invalidateMenuOnExpand() }
}
/**
* Workaround for menu items not disappearing when expanding an expandable item like a SearchView.
* [expandActionViewFromInteraction] should be set to true in [onOptionsItemSelected] when the expandable item is selected

View File

@ -54,6 +54,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.databinding.LibraryControllerBinding
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.base.MaterialFastScroll
import eu.kanade.tachiyomi.ui.base.MaterialMenuSheet
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.category.CategoryController
@ -67,6 +68,7 @@ import eu.kanade.tachiyomi.ui.library.LibraryGroup.UNGROUPED
import eu.kanade.tachiyomi.ui.library.display.TabbedLibraryDisplaySheet
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
import eu.kanade.tachiyomi.ui.main.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
@ -126,6 +128,7 @@ class LibraryController(
LibraryCategoryAdapter.LibraryListener,
BottomSheetController,
RootSearchInterface,
FloatingSearchInterface,
LibraryServiceListener {
init {
@ -209,11 +212,12 @@ class LibraryController(
private var hopperOffset = 0f
override fun getTitle(): String? {
return if (!showCategoryInTitle || binding.headerTitle.text.isNullOrBlank() || binding.recyclerCover.isClickable) {
view?.context?.getString(R.string.library)
} else {
binding.headerTitle.text.toString()
}
setSubtitle()
// return if (!showCategoryInTitle || binding.headerTitle.text.isNullOrBlank() || binding.recyclerCover.isClickable) {
return searchTitle(view?.context?.getString(R.string.library))
// } else {
// binding.headerTitle.text.toString()
// }
}
private var scrollListener = object : RecyclerView.OnScrollListener() {
@ -338,18 +342,30 @@ class LibraryController(
if (currentCategory > -1) {
binding.categoryRecycler.setCategories(currentCategory)
binding.headerTitle.text = presenter.categories[currentCategory].name
setTitle()
setSubtitle()
}
}
fun showMiniBar() {
binding.headerTitle.visibleIf(showCategoryInTitle)
setTitle()
binding.headerCard.visibleIf(showCategoryInTitle)
setSubtitle()
}
private fun setSubtitle() {
if (!singleCategory && presenter.showAllCategories &&
!binding.headerTitle.text.isNullOrBlank() && !binding.recyclerCover.isClickable
) {
activityBinding?.cardToolbar?.subtitle = binding.headerTitle.text.toString()
} else {
activityBinding?.cardToolbar?.subtitle = null
}
}
fun showCategoryText(name: String) {
textAnim?.cancel()
textAnim = binding.jumperCategoryText.animate().alpha(0f).setDuration(250L).setStartDelay(2000)
textAnim = binding.jumperCategoryText.animate().alpha(0f).setDuration(250L).setStartDelay(
2000
)
textAnim?.start()
binding.jumperCategoryText.alpha = 1f
binding.jumperCategoryText.text = name
@ -432,6 +448,7 @@ class LibraryController(
override fun createBinding(inflater: LayoutInflater) = LibraryControllerBinding.inflate(inflater)
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View) {
super.onViewCreated(view)
if (!::presenter.isInitialized) presenter = LibraryPresenter(this)
@ -463,9 +480,15 @@ class LibraryController(
showCategories(false)
}
binding.categoryRecycler.onCategoryClicked = {
binding.libraryGridRecycler.recycler.itemAnimator = null
scrollToHeader(it)
showCategories(show = false)
showCategories(show = false, closeSearch = true)
}
binding.categoryRecycler.setOnTouchListener { _, _ ->
val searchView = activityBinding?.cardToolbar?.menu?.findItem(R.id.action_search)?.actionView
?: return@setOnTouchListener false
val imm = activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
imm!!.hideSoftInputFromWindow(searchView.windowToken, 0)
false
}
binding.categoryRecycler.onShowAllClicked = { isChecked ->
preferences.showAllCategories().set(isChecked)
@ -486,10 +509,12 @@ class LibraryController(
binding.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = binding.libraryGridRecycler.recycler.paddingTop
}
binding.headerTitle.updatePaddingRelative(top = insets.systemWindowInsetTop + 2.dpToPx)
binding.headerCard.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.systemWindowInsetTop + 4.dpToPx
}
},
onLeavingController = {
binding.headerTitle.gone()
binding.headerCard.gone()
},
onBottomNavUpdate = {
updateFilterSheetY()
@ -616,7 +641,7 @@ class LibraryController(
3 -> showGroupOptions()
2 -> showDisplayOptions()
1 -> if (canCollapseOrExpandCategory() != null) presenter.toggleAllCategoryVisibility()
else -> activityBinding?.toolbar?.menu?.performIdentifierAction(
else -> activityBinding?.cardToolbar?.menu?.performIdentifierAction(
R.id.action_search,
0
)
@ -779,7 +804,12 @@ class LibraryController(
view.elevation = 15f.dpToPx
setAction(R.string.cancel) {
LibraryUpdateService.stop(context)
Handler().post { NotificationReceiver.dismissNotification(context, Notifications.ID_LIBRARY_PROGRESS) }
Handler().post {
NotificationReceiver.dismissNotification(
context,
Notifications.ID_LIBRARY_PROGRESS
)
}
}
}
}
@ -906,7 +936,9 @@ class LibraryController(
binding.progress.gone()
if (!freshStart) {
justStarted = false
if (binding.recyclerLayout.alpha == 0f) binding.recyclerLayout.animate().alpha(1f).setDuration(500)
if (binding.recyclerLayout.alpha == 0f) binding.recyclerLayout.animate().alpha(1f).setDuration(
500
)
.start()
} else binding.recyclerLayout.alpha = 1f
if (justStarted && freshStart) {
@ -942,6 +974,7 @@ class LibraryController(
showSlideAnimation()
}
}
setSubtitle()
showMiniBar()
}
}
@ -985,9 +1018,12 @@ class LibraryController(
.setDuration(duration)
}
private fun showCategories(show: Boolean) {
private fun showCategories(show: Boolean, closeSearch: Boolean = false) {
binding.recyclerCover.isClickable = show
binding.recyclerCover.isFocusable = show
if (closeSearch) {
activityBinding?.cardToolbar?.menu?.findItem(R.id.action_search)?.collapseActionView()
}
val full = binding.categoryRecycler.height.toFloat() + binding.libraryGridRecycler.recycler.paddingTop
val translateY = if (show) full else 0f
binding.libraryGridRecycler.recycler.animate().translationY(translateY).apply {
@ -1002,7 +1038,7 @@ class LibraryController(
binding.libraryGridRecycler.recycler.suppressLayout(show)
activityBinding?.toolbar?.showDropdown(!show)
binding.swipeRefresh.isEnabled = !show
setTitle()
setSubtitle()
if (show) {
binding.categoryRecycler.scrollToCategory(activeCategory)
binding.fastScroller.hideScrollbar()
@ -1075,7 +1111,10 @@ class LibraryController(
(binding.libraryGridRecycler.recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
binding.libraryGridRecycler.recycler.adapter = adapter
(binding.libraryGridRecycler.recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
(binding.libraryGridRecycler.recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
position,
0
)
}
fun search(query: String?): Boolean {
@ -1085,7 +1124,9 @@ class LibraryController(
adapter.addScrollableHeader(searchItem)
} else if (this.query.isNotBlank()) {
searchItem.string = this.query
(binding.libraryGridRecycler.recycler.findViewHolderForAdapterPosition(0) as? SearchGlobalItem.Holder)?.bind(this.query)
(binding.libraryGridRecycler.recycler.findViewHolderForAdapterPosition(0) as? SearchGlobalItem.Holder)?.bind(
this.query
)
} else if (this.query.isBlank() && adapter.scrollableHeaders.isNotEmpty()) {
adapter.removeAllScrollableHeaders()
}
@ -1264,7 +1305,10 @@ class LibraryController(
) ||
adapter.getItem(fromPosition) == null
) {
binding.libraryGridRecycler.recycler.scrollBy(0, binding.libraryGridRecycler.recycler.paddingTop)
binding.libraryGridRecycler.recycler.scrollBy(
0,
binding.libraryGridRecycler.recycler.paddingTop
)
}
if (lastItemPosition == toPosition) lastItemPosition = null
else if (lastItemPosition == null) lastItemPosition = fromPosition
@ -1481,8 +1525,26 @@ class LibraryController(
searchView.clearFocus()
}
setOnQueryTextChangeListener(searchView) { search(it) }
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
setOnQueryTextChangeListener(searchView) {
if (!it.isNullOrEmpty() && binding.recyclerCover.isClickable) {
showCategories(false)
}
search(it)
}
searchItem.fixExpand(
onExpand = {
if (!binding.recyclerCover.isClickable && query.isBlank()) {
showCategories(true)
}
invalidateMenuOnExpand()
},
onCollapse = {
if (binding.recyclerCover.isClickable) {
showCategories(false)
}
true
}
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {

View File

@ -12,6 +12,7 @@ import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.view.GestureDetector
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
@ -21,6 +22,7 @@ import android.view.WindowManager
import android.webkit.WebView
import androidx.annotation.IdRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.GestureDetectorCompat
@ -112,6 +114,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER
var tabAnimation: ValueAnimator? = null
var overflowDialog: Dialog? = null
var currentToolbar: Toolbar? = null
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
this.snackBar = snackBar
@ -145,7 +148,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
binding = MainActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
setFloatingToolbar(true)
drawerArrow = DrawerArrowDrawable(this)
drawerArrow?.color = getResourceColor(R.attr.actionBarTintColor)
@ -270,6 +273,17 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} else onBackPressed()
}
binding.cardToolbar.setNavigationOnClickListener {
val rootSearchController = router.backstack.lastOrNull()?.controller()
if (rootSearchController is RootSearchInterface) {
rootSearchController.expandSearch()
} else onBackPressed()
}
binding.cardToolbar.setOnClickListener {
binding.cardToolbar.menu.findItem(R.id.action_search)?.expandActionView()
}
binding.bottomNav.visibleIf(!hideBottomNav)
binding.bottomView.visibility = if (hideBottomNav) View.GONE else binding.bottomView.visibility
binding.bottomNav.alpha = if (hideBottomNav) 0f else 1f
@ -325,12 +339,42 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
}
preferences.incognitoMode()
.asImmediateFlow { binding.toolbar.setIncognitoMode(it) }
.asImmediateFlow {
binding.toolbar.setIncognitoMode(it)
binding.cardToolbar.setIncognitoMode(it)
}
.launchIn(lifecycleScope)
setExtensionsBadge()
}
fun setFloatingToolbar(show: Boolean, solidBG: Boolean = false) {
val oldTB = currentToolbar
currentToolbar = if (show) {
binding.cardToolbar
} else {
binding.toolbar
}
if (oldTB != currentToolbar) {
setSupportActionBar(currentToolbar)
}
binding.toolbar.isVisible = !show
binding.cardFrame.isVisible = show
binding.appBar.setBackgroundColor(
if (show && !solidBG) Color.TRANSPARENT else getResourceColor(R.attr.colorSecondary)
)
currentToolbar?.setNavigationOnClickListener {
val rootSearchController = router.backstack.lastOrNull()?.controller()
if (rootSearchController is RootSearchInterface) {
rootSearchController.expandSearch()
} else onBackPressed()
}
if (oldTB != currentToolbar) {
invalidateOptionsMenu()
}
}
fun setDismissIcon(enabled: Boolean) {
binding.cardToolbar.navigationIcon = if (enabled) dismissDrawable else searchDrawable
binding.toolbar.navigationIcon = if (enabled) dismissDrawable else searchDrawable
}
@ -553,6 +597,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
DownloadService.removeListener(this)
if (isBindingInitialized) {
binding.toolbar.setNavigationOnClickListener(null)
binding.cardToolbar.setNavigationOnClickListener(null)
}
}
@ -608,6 +653,12 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
router.setRoot(controller.withFadeTransaction().tag(id.toString()))
}
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
val searchItem = menu?.findItem(R.id.action_search)
searchItem?.isVisible = currentToolbar != binding.cardToolbar
return super.onPrepareOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
// Initialize option to open catalogue settings.
@ -660,6 +711,9 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
return super.dispatchTouchEvent(ev)
}
protected fun canShowFloatingToolbar(controller: Controller?) =
controller is FloatingSearchInterface
protected open fun syncActivityViewWithController(
to: Controller?,
from: Controller? = null,
@ -668,14 +722,18 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
if (from is DialogController || to is DialogController) {
return
}
setFloatingToolbar(canShowFloatingToolbar(to))
val onRoot = router.backstackSize == 1
if (onRoot) {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
binding.toolbar.navigationIcon = searchDrawable
binding.cardToolbar.navigationIcon = searchDrawable
} else {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
binding.toolbar.navigationIcon = drawerArrow
binding.cardToolbar.navigationIcon = drawerArrow
}
binding.cardToolbar.subtitle = null
drawerArrow?.progress = 1f
binding.bottomNav.visibility = if (!hideBottomNav) View.VISIBLE else binding.bottomNav.visibility
@ -803,8 +861,19 @@ interface BottomNavBarInterface {
interface RootSearchInterface {
fun expandSearch() {
if (this is Controller) (activity as? MainActivity)?.binding?.toolbar?.menu?.findItem(R.id.action_search)
?.expandActionView()
if (this is Controller) {
val mainActivity = activity as? MainActivity ?: return
mainActivity.binding.cardToolbar.menu.findItem(R.id.action_search)?.expandActionView()
}
}
}
interface FloatingSearchInterface {
fun searchTitle(title: String?): String? {
if (this is Controller) {
return activity?.getString(R.string.search_, title)
}
return title
}
}

View File

@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import uy.kohesive.injekt.injectLazy
import kotlin.math.max
class OverflowDialog(activity: MainActivity) : Dialog(activity, R.style.OverflowDialogTheme) {
@ -76,7 +77,7 @@ class OverflowDialog(activity: MainActivity) : Dialog(activity, R.style.Overflow
}
binding.overflowCardView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = activity.binding.toolbar.height - 2.dpToPx
topMargin = max(activity.binding.toolbar.height, activity.binding.cardFrame.height) - 2.dpToPx
}
window?.let { window ->
window.navigationBarColor = Color.TRANSPARENT

View File

@ -25,9 +25,9 @@ class SearchActivity : MainActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.toolbar.navigationIcon = drawerArrow
binding.toolbar.setNavigationOnClickListener {
popToRoot()
}
binding.cardToolbar.navigationIcon = drawerArrow
binding.toolbar.setNavigationOnClickListener { popToRoot() }
binding.cardToolbar.setNavigationOnClickListener { popToRoot() }
(router.backstack.lastOrNull()?.controller() as? BaseController<*>)?.setTitle()
(router.backstack.lastOrNull()?.controller() as? SettingsController)?.setTitle()
}
@ -63,6 +63,8 @@ class SearchActivity : MainActivity() {
if (from is DialogController || to is DialogController) {
return
}
setFloatingToolbar(canShowFloatingToolbar(to))
binding.cardToolbar.navigationIcon = drawerArrow
binding.toolbar.navigationIcon = drawerArrow
drawerArrow?.progress = 1f

View File

@ -69,6 +69,7 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterHolder
@ -445,9 +446,10 @@ class MangaDetailsController :
if (router.backstackSize > 0 &&
router.backstack.last().controller() !is MangaDetailsController
) {
activityBinding?.appBar?.setBackgroundColor(colorSecondary)
if (router.backstack.last().controller() !is FloatingSearchInterface) {
activityBinding?.appBar?.setBackgroundColor(colorSecondary)
}
activityBinding?.toolbar?.setBackgroundColor(colorSecondary)
activity?.window?.statusBarColor = activity?.getResourceColor(
android.R.attr.statusBarColor
) ?: colorSecondary

View File

@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.databinding.RecentsControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.main.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
@ -74,6 +75,7 @@ class RecentsController(bundle: Bundle? = null) :
FlexibleAdapter.OnItemMoveListener,
FlexibleAdapter.EndlessScrollListener,
RootSearchInterface,
FloatingSearchInterface,
BottomSheetController,
RemoveHistoryDialog.Listener {
@ -100,11 +102,16 @@ class RecentsController(bundle: Bundle? = null) :
private var lastChapterId: Long? = null
private var showingDownloads = false
var headerHeight = 0
private var query = ""
set(value) {
field = value
presenter.query = value
}
override fun getTitle(): String? {
return if (showingDownloads) {
resources?.getString(R.string.download_queue)
} else resources?.getString(R.string.recents)
} else searchTitle(resources?.getString(R.string.recents))
}
override fun createBinding(inflater: LayoutInflater) = RecentsControllerBinding.inflate(inflater)
@ -230,7 +237,7 @@ class RecentsController(bundle: Bundle? = null) :
val oldShow = showingDownloads
showingDownloads = progress > 0.92f
if (oldShow != showingDownloads) {
setTitle()
updateTitleAndMenu()
activity?.invalidateOptionsMenu()
}
}
@ -242,7 +249,7 @@ class RecentsController(bundle: Bundle? = null) :
binding.downloadBottomSheet.sheetLayout.alpha =
if (state == BottomSheetBehavior.STATE_COLLAPSED) 1f else 0f
showingDownloads = state == BottomSheetBehavior.STATE_EXPANDED
setTitle()
updateTitleAndMenu()
activity?.invalidateOptionsMenu()
}
@ -299,6 +306,11 @@ class RecentsController(bundle: Bundle? = null) :
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
}
fun updateTitleAndMenu() {
(activity as? MainActivity)?.setFloatingToolbar(!showingDownloads, true)
setTitle()
}
private fun setBottomPadding() {
val bottomBar = activityBinding?.bottomNav ?: return
val pad = bottomBar.translationY - bottomBar.height
@ -554,7 +566,7 @@ class RecentsController(bundle: Bundle? = null) :
(activity as? MainActivity)?.setUndoSnackBar(snack)
}
override fun isSearching() = presenter.query.isNotEmpty()
override fun isSearching() = query.isNotEmpty()
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
if (onRoot) (activity as? MainActivity)?.setDismissIcon(showingDownloads)
@ -566,20 +578,22 @@ class RecentsController(bundle: Bundle? = null) :
val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView
searchView.queryHint = view?.context?.getString(R.string.search_recents)
searchItem.collapseActionView()
if (isSearching()) {
searchItem.expandActionView()
searchView.setQuery(presenter.query, true)
searchView.setQuery(query, true)
searchView.clearFocus()
}
setOnQueryTextChangeListener(searchView) {
if (presenter.query != it) {
presenter.query = it ?: return@setOnQueryTextChangeListener false
if (query != it) {
query = it ?: return@setOnQueryTextChangeListener false
// loadNoMore()
resetProgressItem()
refresh()
}
true
}
searchItem.fixExpandInvalidate()
}
}
@ -636,7 +650,12 @@ class RecentsController(bundle: Bundle? = null) :
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeEnded(handler, type)
if (type == ControllerChangeType.POP_ENTER) setBottomPadding()
if (type == ControllerChangeType.POP_ENTER) {
setBottomPadding()
}
if (type.isEnter) {
updateTitleAndMenu()
}
}
fun hasQueue() = presenter.downloadManager.hasQueue()
@ -659,7 +678,7 @@ class RecentsController(bundle: Bundle? = null) :
if (showingDownloads) {
binding.downloadBottomSheet.dlBottomSheet.dismiss()
} else {
activityBinding?.toolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
activityBinding?.cardToolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
}
}

View File

@ -20,6 +20,7 @@ import com.bluelinelabs.conductor.ControllerChangeType
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.util.view.scrollViewWith
import kotlinx.coroutines.MainScope
import rx.Observable
@ -96,6 +97,9 @@ abstract class SettingsController : PreferenceController() {
}
open fun getTitle(): String? {
if (this is FloatingSearchInterface) {
return searchTitle(preferenceScreen?.title?.toString())
}
return preferenceScreen?.title?.toString()
}

View File

@ -8,11 +8,12 @@ import androidx.preference.PreferenceScreen
import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.RouterTransaction
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchController
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.withFadeTransaction
class SettingsMainController : SettingsController() {
class SettingsMainController : SettingsController(), FloatingSearchInterface {
init {
setHasOptionsMenu(true)

View File

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.SettingsSearchControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.setting.SettingsController
import eu.kanade.tachiyomi.util.view.liftAppbarWith
import eu.kanade.tachiyomi.util.view.withFadeTransaction
@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.util.view.withFadeTransaction
*/
class SettingsSearchController :
NucleusController<SettingsSearchControllerBinding, SettingsSearchPresenter>(),
FloatingSearchInterface,
SettingsSearchAdapter.OnTitleClickListener {
/**
@ -107,7 +109,7 @@ class SettingsSearchController :
adapter = SettingsSearchAdapter(this)
liftAppbarWith(binding.recycler)
liftAppbarWith(binding.recycler, true)
// Create recycler and set adapter.
binding.recycler.layoutManager = LinearLayoutManager(view.context)
binding.recycler.adapter = adapter

View File

@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController
import eu.kanade.tachiyomi.ui.main.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.setting.SettingsBrowseController
@ -59,8 +60,8 @@ import kotlinx.android.parcel.Parcelize
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Date
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
/**
* This controller shows and manages the different catalogues enabled by the user.
@ -73,6 +74,7 @@ class BrowseController :
FlexibleAdapter.OnItemClickListener,
SourceAdapter.SourceListener,
RootSearchInterface,
FloatingSearchInterface,
BottomSheetController {
/**
@ -109,7 +111,7 @@ class BrowseController :
else -> R.string.source_migration
}
)
} else view?.context?.getString(R.string.browse)
} else searchTitle(view?.context?.getString(R.string.sources))
}
val presenter = SourcePresenter(this)
@ -142,19 +144,6 @@ class BrowseController :
bottom = (activityBinding?.bottomNav?.height ?: 0) + 58.spToPx
)
},
liftOnScroll = { el ->
if (!binding.bottomSheet.root.sheetBehavior.isExpanded()) {
elevationAnim?.cancel()
elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f,
if (el) 15f else 0f
)
elevationAnim?.addUpdateListener { valueAnimator ->
activityBinding?.appBar?.elevation = valueAnimator.animatedValue as Float
}
elevationAnim?.start()
}
},
onBottomNavUpdate = {
setBottomPadding()
}
@ -162,33 +151,31 @@ class BrowseController :
binding.sourceRecycler.post {
setBottomSheetTabs(if (binding.bottomSheet.root.sheetBehavior.isCollapsed()) 0f else 1f)
activityBinding?.appBar?.elevation = min(
if (binding.bottomSheet.root.sheetBehavior.isCollapsed()) 0f else 1f * 15f,
if (binding.sourceRecycler.canScrollVertically(-1)) 15f else 0f
)
binding.sourceRecycler.updatePaddingRelative(
bottom = (activityBinding?.bottomNav?.height ?: 0) + 58.spToPx
)
val isCollapsed = binding.bottomSheet.root.sheetBehavior.isCollapsed()
binding.shadow.alpha = if (isCollapsed) 0.5f else 0f
updateTitleAndMenu()
}
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
binding.bottomSheet.root.onCreate(this)
binding.shadow.alpha =
if (binding.bottomSheet.root.sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 0f
binding.bottomSheet.root.sheetBehavior?.addBottomSheetCallback(
object : BottomSheetBehavior
.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, progress: Float) {
binding.shadow2.alpha = (1 - max(0f, progress)) * 0.25f
activityBinding?.appBar?.elevation = min(
(1f - progress) * 15f,
if (binding.sourceRecycler.canScrollVertically(-1)) 15f else 0f
)
binding.shadow.alpha = (1 - abs(progress)) * 0.5f
activityBinding?.appBar?.y = max(activityBinding!!.appBar.y, -headerHeight * (1 - progress))
val oldShow = showingExtensions
showingExtensions = progress > 0.92f
if (oldShow != showingExtensions) {
setTitle()
activity?.invalidateOptionsMenu()
updateTitleAndMenu()
}
setBottomSheetTabs(max(0f, progress))
}
@ -209,11 +196,15 @@ class BrowseController :
) {
binding.bottomSheet.root.sheetBehavior?.isDraggable = true
showingExtensions = state == BottomSheetBehavior.STATE_EXPANDED
setTitle()
updateTitleAndMenu()
if (state == BottomSheetBehavior.STATE_EXPANDED) {
extBottomSheet.fetchOnlineExtensionsIfNeeded()
} else extBottomSheet.shouldCallApi = true
activity?.invalidateOptionsMenu()
}
if (state == BottomSheetBehavior.STATE_EXPANDED || state == BottomSheetBehavior.STATE_COLLAPSED) {
binding.shadow.alpha =
if (state == BottomSheetBehavior.STATE_COLLAPSED) 0.5f else 0f
}
retainViewMode = if (state == BottomSheetBehavior.STATE_EXPANDED) {
@ -238,8 +229,9 @@ class BrowseController :
}
fun updateTitleAndMenu() {
setTitle()
(activity as? MainActivity)?.setFloatingToolbar(!showingExtensions)
activity?.invalidateOptionsMenu()
setTitle()
}
fun setBottomSheetTabs(progress: Float) {
@ -348,20 +340,9 @@ class BrowseController :
}
if (!type.isEnter) {
binding.bottomSheet.root.canExpand = false
activityBinding?.appBar?.elevation =
when {
binding.bottomSheet.root.sheetBehavior.isExpanded() -> 0f
binding.sourceRecycler.canScrollVertically(-1) -> 15f
else -> 0f
}
} else {
binding.bottomSheet.root.presenter.refreshMigrations()
activityBinding?.appBar?.elevation =
when {
binding.bottomSheet.root.sheetBehavior.isExpanded() -> 0f
binding.sourceRecycler.canScrollVertically(-1) -> 15f
else -> 0f
}
updateTitleAndMenu()
}
setBottomPadding()
}
@ -458,7 +439,7 @@ class BrowseController :
override fun expandSearch() {
if (showingExtensions) binding.bottomSheet.root.sheetBehavior?.collapse()
else activityBinding?.toolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
else activityBinding?.cardToolbar?.menu?.findItem(R.id.action_search)?.expandActionView()
}
/**
@ -480,13 +461,19 @@ class BrowseController :
// Change hint to show global search.
searchView.queryHint = view?.context?.getString(R.string.search_extensions)
searchItem.collapseActionView()
if (extQuery.isNotEmpty()) {
searchItem.expandActionView()
searchView.setQuery(extQuery, true)
searchView.clearFocus()
}
// Create query listener which opens the global search view.
setOnQueryTextChangeListener(searchView) {
extQuery = it ?: ""
binding.bottomSheet.root.drawExtensions()
true
}
searchItem.fixExpandInvalidate()
} else {
inflater.inflate(R.menu.migration_main, menu)
}

View File

@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.source.BrowseController
@ -57,6 +58,7 @@ open class BrowseSourceController(bundle: Bundle) :
NucleusController<BrowseSourceControllerBinding, BrowseSourcePresenter>(bundle),
FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener,
FloatingSearchInterface,
FlexibleAdapter.EndlessScrollListener {
constructor(
@ -118,7 +120,7 @@ open class BrowseSourceController(bundle: Bundle) :
}
override fun getTitle(): String? {
return presenter.source.name
return searchTitle(presenter.source.name)
}
override fun createPresenter(): BrowseSourcePresenter {

View File

@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.SourceGlobalSearchControllerBinding
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
@ -34,6 +35,7 @@ open class GlobalSearchController(
protected val initialQuery: String? = null,
protected val extensionFilter: String? = null
) : NucleusController<SourceGlobalSearchControllerBinding, GlobalSearchPresenter>(),
FloatingSearchInterface,
GlobalSearchCardAdapter.OnMangaClickListener {
/**

View File

@ -26,7 +26,9 @@ import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MainActivityBinding
import eu.kanade.tachiyomi.ui.base.MaterialFastScroll
import eu.kanade.tachiyomi.ui.main.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.util.system.dpToPx
@ -67,15 +69,60 @@ fun Controller.setOnQueryTextChangeListener(
)
}
fun Controller.liftAppbarWith(recycler: RecyclerView) {
view?.applyWindowInsetsForController()
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
fun Controller.removeQueryListener() {
val searchView = activityBinding?.cardToolbar?.menu?.findItem(R.id.action_search)?.actionView as? SearchView
val searchView2 = activityBinding?.toolbar?.menu?.findItem(R.id.action_search)?.actionView as? SearchView
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?) = true
override fun onQueryTextChange(newText: String?) = true
})
searchView2?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?) = true
override fun onQueryTextChange(newText: String?) = true
})
}
fun Controller.liftAppbarWith(recycler: RecyclerView, padView: Boolean = false) {
if (padView) {
val attrsArray = intArrayOf(R.attr.actionBarSize)
val array = recycler.context.obtainStyledAttributes(attrsArray)
var appBarHeight = (
if (activityBinding?.toolbar?.height ?: 0 > 0) activityBinding!!.toolbar.height
else array.getDimensionPixelSize(0, 0)
)
array.recycle()
activityBinding!!.toolbar.post {
if (activityBinding!!.toolbar.height > 0) {
appBarHeight = activityBinding!!.toolbar.height
recycler.requestApplyInsets()
}
}
recycler.updatePaddingRelative(
top = activityBinding!!.toolbar.y.toInt() + appBarHeight
)
recycler.doOnApplyWindowInsets { view, insets, _ ->
val headerHeight = insets.systemWindowInsetTop + appBarHeight
view.updatePaddingRelative(
top = headerHeight,
bottom = insets.systemWindowInsetBottom
)
}
} else {
view?.applyWindowInsetsForController()
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
}
var elevationAnim: ValueAnimator? = null
var elevate = false
val elevateFunc: (Boolean) -> Unit = { el ->
val elevateFunc: (Boolean) -> Unit = f@{ el ->
elevate = el
elevationAnim?.cancel()
val floatingBar =
!(activityBinding?.toolbar?.isVisible == true || activityBinding?.tabsFrameLayout?.isVisible == true)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
return@f
}
elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f,
if (el) 15f else 0f
@ -85,6 +132,12 @@ fun Controller.liftAppbarWith(recycler: RecyclerView) {
}
elevationAnim?.start()
}
val floatingBar =
!(activityBinding?.toolbar?.isVisible == true || activityBinding?.tabsFrameLayout?.isVisible == true)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
}
elevateFunc(recycler.canScrollVertically(-1))
recycler.addOnScrollListener(
object : RecyclerView.OnScrollListener() {
@ -163,12 +216,21 @@ fun Controller.scrollViewWith(
var elevate = false
var isInView = true
val preferences: PreferencesHelper by injectLazy()
val elevateFunc: (Boolean) -> Unit = { el ->
val elevateFunc: (Boolean) -> Unit = f@{ el ->
elevate = el
if (liftOnScroll != null) {
liftOnScroll.invoke(el)
} else {
elevationAnim?.cancel()
val floatingBar =
!(
activityBinding?.toolbar?.isVisible == true ||
(activityBinding?.tabsFrameLayout?.isVisible == true && includeTabView)
)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
return@f
}
elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f,
if (el) 15f else 0f
@ -179,6 +241,14 @@ fun Controller.scrollViewWith(
elevationAnim?.start()
}
}
val floatingBar =
!(
activityBinding?.toolbar?.isVisible == true ||
(activityBinding?.tabsFrameLayout?.isVisible == true && includeTabView)
)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
}
addLifecycleListener(
object : Controller.LifecycleListener() {
override fun onChangeStart(
@ -211,8 +281,10 @@ fun Controller.scrollViewWith(
}
} else {
if (!customPadding && lastY == 0f && (
router.backstack.lastOrNull()
?.controller() is MangaDetailsController || includeTabView
(
this@scrollViewWith !is FloatingSearchInterface && router.backstack.lastOrNull()
?.controller() is MangaDetailsController
) || includeTabView
)
) {
val parent = recycler.parent as? ViewGroup ?: return

View File

@ -62,27 +62,37 @@
android:layout_height="match_parent"
app:fastScrollerBubbleEnabled="true" />
<TextView
android:id="@+id/header_title"
style="@style/TextAppearance.MaterialComponents.Headline6"
android:layout_width="match_parent"
<androidx.cardview.widget.CardView
android:id="@+id/header_card"
android:layout_marginTop="6dp"
app:cardCornerRadius="16dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:background="@drawable/list_item_selector"
android:backgroundTint="?colorSecondary"
android:clickable="true"
android:elevation="5dp"
android:ellipsize="end"
android:focusable="true"
android:gravity="center"
android:inputType="none"
android:maxLines="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp"
android:textColor="?actionBarTintColor"
android:textSize="14sp"
tools:text="Category" />
android:layout_gravity="center|top">
<TextView
android:id="@+id/header_title"
style="@style/TextAppearance.MaterialComponents.Headline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/list_item_selector"
android:backgroundTint="?colorPrimaryVariant"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:inputType="none"
android:maxLines="1"
android:textAlignment="center"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:textColor="?actionBarTintColor"
android:textSize="14sp"
tools:text="Category" />
</androidx.cardview.widget.CardView>
<eu.kanade.tachiyomi.widget.EmptyView
android:id="@+id/empty_view"
@ -116,6 +126,7 @@
<FrameLayout
android:id="@+id/category_hopper_frame"
android:layout_width="wrap_content"
tools:translationY="400dp"
android:layout_height="wrap_content"
android:layout_gravity="top|center">

View File

@ -38,22 +38,106 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorSecondary">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/toolbar_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="?actionBarTintColor"
android:ellipsize="end"
android:layout_gravity="center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="20sp"
tools:drawableEnd="@drawable/ic_arrow_drop_down_24dp"
tools:drawableStart="@drawable/ic_blank_24dp"
tools:text="Title Text" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/toolbar_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="?actionBarTintColor"
android:ellipsize="end"
android:layout_gravity="center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="20sp"
tools:drawableEnd="@drawable/ic_arrow_drop_down_24dp"
tools:drawableStart="@drawable/ic_blank_24dp"
tools:text="Title Text" />
</eu.kanade.tachiyomi.ui.base.CenteredToolbar>
<FrameLayout
android:id="@+id/card_frame"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" >
<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_marginTop="4dp"
app:cardBackgroundColor="?colorPrimaryVariant"
android:layout_marginBottom="4dp"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
app:cardCornerRadius="8dp"
android:layout_height="match_parent" >
<eu.kanade.tachiyomi.ui.base.FloatingToolbar
android:id="@+id/card_toolbar"
tools:title="Search Library..."
app:contentInsetStartWithNavigation="0dp"
app:contentInsetEndWithActions="0dp"
app:contentInsetStart="0dp"
app:contentInsetEnd="0dp"
app:navigationIconTint="@color/text_color_secondary"
app:navigationIcon="@drawable/ic_search_24dp"
app:titleTextAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:subtitleTextAppearance="@style/TextAppearance.MaterialComponents.Caption"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center"
android:orientation="horizontal">
<ImageView
android:id="@+id/card_incog_image"
app:tint="?actionBarTintColor"
android:layout_gravity="center|start"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="0dp"
android:contentDescription="@string/incognito_mode"
android:src="@drawable/ic_incognito_circle_24dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/card_title"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="?actionBarTintColor"
android:ellipsize="end"
android:layout_gravity="center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="20sp"
tools:drawableEnd="@drawable/ic_arrow_drop_down_24dp"
tools:drawableStart="@drawable/ic_blank_24dp"
tools:text="Title Text" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/card_subtitle"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:layout_gravity="start|center"
android:maxLines="1"
android:textColor="?actionBarTintColor"
android:textSize="12sp"
tools:text="Title Text" />
</LinearLayout>
</LinearLayout>
</eu.kanade.tachiyomi.ui.base.FloatingToolbar>
</androidx.cardview.widget.CardView>
</FrameLayout>
<FrameLayout
android:id="@+id/tabs_frame_layout"
android:clickable="true"

View File

@ -20,7 +20,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="6dp"
android:layout_marginEnd="14dp"
android:background="?android:attr/colorBackground"
app:cardBackgroundColor="?android:attr/colorBackground"
app:cardCornerRadius="12dp"

View File

@ -7,7 +7,7 @@
android:id="@+id/action_search"
android:icon="@drawable/ic_search_24dp"
android:title="@string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"
app:showAsAction="collapseActionView|ifRoom" />
<item

View File

@ -8,7 +8,7 @@
android:icon="@drawable/ic_search_24dp"
android:visible="false"
app:showAsAction="collapseActionView|ifRoom"
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"/>
<item android:id="@+id/action_filter"
android:title="@string/filter"

View File

@ -7,5 +7,5 @@
android:title="@string/search"
android:icon="@drawable/ic_search_24dp"
app:showAsAction="collapseActionView|ifRoom"
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"/>
</menu>

View File

@ -9,7 +9,7 @@
android:icon="@drawable/ic_search_24dp"
android:title="@string/search"
android:visible="false"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"
app:showAsAction="collapseActionView|ifRoom" />

View File

@ -7,7 +7,7 @@
android:icon="@drawable/ic_search_24dp"
android:title="@string/search"
android:visible="false"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"
app:showAsAction="ifRoom|collapseActionView" />
<item

View File

@ -6,6 +6,6 @@
android:id="@+id/action_search"
android:icon="@drawable/ic_search_24dp"
android:title="@string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:actionViewClass="eu.kanade.tachiyomi.ui.base.MiniSearchView"
app:showAsAction="collapseActionView|ifRoom" />
</menu>

View File

@ -902,6 +902,7 @@
<string name="rotation">Rotation</string>
<string name="save">Save</string>
<string name="search">Search</string>
<string name="search_">Search %1$s</string>
<string name="select_all">Select all</string>
<string name="select_none">Select none</string>
<string name="selection">Selection</string>