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.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.Gravity import android.view.Gravity
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams import androidx.core.view.updateLayoutParams
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.textview.MaterialTextView import com.google.android.material.textview.MaterialTextView
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
@ -17,25 +13,8 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
@SuppressLint("CustomViewStyleable") @SuppressLint("CustomViewStyleable")
class CenteredToolbar@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : 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() { override fun onFinishInflate() {
super.onFinishInflate() super.onFinishInflate()
toolbarTitle = findViewById<MaterialTextView>(R.id.toolbar_title) 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)) toolbarTitle.setTextColor(context.getResourceColor(R.attr.actionBarTintColor))
} }
override fun setTitle(resId: Int) { override fun setCustomTitle(title: CharSequence?) {
setCustomTitle(context.getString(resId)) super.setCustomTitle(title)
}
override fun setTitle(title: CharSequence?) {
setCustomTitle(title)
}
private fun setCustomTitle(title: CharSequence?) {
toolbarTitle.isVisible = true
toolbarTitle.text = title
super.setTitle(null)
toolbarTitle.updateLayoutParams<LayoutParams> { toolbarTitle.updateLayoutParams<LayoutParams> {
gravity = if (navigationIcon is DrawerArrowDrawable) Gravity.START else Gravity.CENTER gravity = if (navigationIcon is DrawerArrowDrawable) Gravity.START else Gravity.CENTER
} }
toolbarTitle.compoundDrawablePadding = if (navigationIcon is DrawerArrowDrawable) 6.dpToPx else 0 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 package eu.kanade.tachiyomi.ui.base.controller
import android.app.Activity
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
@ -11,6 +12,7 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RestoreViewOnCreateController import com.bluelinelabs.conductor.RestoreViewOnCreateController
import eu.kanade.tachiyomi.util.view.removeQueryListener
import timber.log.Timber import timber.log.Timber
abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) : 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) { override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
if (type.isEnter) { if (type.isEnter) {
setTitle() setTitle()
} else {
removeQueryListener()
} }
setHasOptionsMenu(type.isEnter) setHasOptionsMenu(type.isEnter)
super.onChangeStarted(handler, type) super.onChangeStarted(handler, type)
@ -69,6 +73,11 @@ abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
return null return null
} }
override fun onActivityPaused(activity: Activity) {
super.onActivityPaused(activity)
removeQueryListener()
}
fun setTitle() { fun setTitle() {
var parentController = parentController var parentController = parentController
while (parentController != null) { 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. * 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 * [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.data.preference.getOrDefault
import eu.kanade.tachiyomi.databinding.LibraryControllerBinding import eu.kanade.tachiyomi.databinding.LibraryControllerBinding
import eu.kanade.tachiyomi.source.LocalSource 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.MaterialMenuSheet
import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.category.CategoryController 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.display.TabbedLibraryDisplaySheet
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
import eu.kanade.tachiyomi.ui.main.BottomSheetController 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.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
@ -126,6 +128,7 @@ class LibraryController(
LibraryCategoryAdapter.LibraryListener, LibraryCategoryAdapter.LibraryListener,
BottomSheetController, BottomSheetController,
RootSearchInterface, RootSearchInterface,
FloatingSearchInterface,
LibraryServiceListener { LibraryServiceListener {
init { init {
@ -209,11 +212,12 @@ class LibraryController(
private var hopperOffset = 0f private var hopperOffset = 0f
override fun getTitle(): String? { override fun getTitle(): String? {
return if (!showCategoryInTitle || binding.headerTitle.text.isNullOrBlank() || binding.recyclerCover.isClickable) { setSubtitle()
view?.context?.getString(R.string.library) // return if (!showCategoryInTitle || binding.headerTitle.text.isNullOrBlank() || binding.recyclerCover.isClickable) {
} else { return searchTitle(view?.context?.getString(R.string.library))
binding.headerTitle.text.toString() // } else {
} // binding.headerTitle.text.toString()
// }
} }
private var scrollListener = object : RecyclerView.OnScrollListener() { private var scrollListener = object : RecyclerView.OnScrollListener() {
@ -338,18 +342,30 @@ class LibraryController(
if (currentCategory > -1) { if (currentCategory > -1) {
binding.categoryRecycler.setCategories(currentCategory) binding.categoryRecycler.setCategories(currentCategory)
binding.headerTitle.text = presenter.categories[currentCategory].name binding.headerTitle.text = presenter.categories[currentCategory].name
setTitle() setSubtitle()
} }
} }
fun showMiniBar() { fun showMiniBar() {
binding.headerTitle.visibleIf(showCategoryInTitle) binding.headerCard.visibleIf(showCategoryInTitle)
setTitle() 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) { fun showCategoryText(name: String) {
textAnim?.cancel() textAnim?.cancel()
textAnim = binding.jumperCategoryText.animate().alpha(0f).setDuration(250L).setStartDelay(2000) textAnim = binding.jumperCategoryText.animate().alpha(0f).setDuration(250L).setStartDelay(
2000
)
textAnim?.start() textAnim?.start()
binding.jumperCategoryText.alpha = 1f binding.jumperCategoryText.alpha = 1f
binding.jumperCategoryText.text = name binding.jumperCategoryText.text = name
@ -432,6 +448,7 @@ class LibraryController(
override fun createBinding(inflater: LayoutInflater) = LibraryControllerBinding.inflate(inflater) override fun createBinding(inflater: LayoutInflater) = LibraryControllerBinding.inflate(inflater)
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View) { override fun onViewCreated(view: View) {
super.onViewCreated(view) super.onViewCreated(view)
if (!::presenter.isInitialized) presenter = LibraryPresenter(this) if (!::presenter.isInitialized) presenter = LibraryPresenter(this)
@ -463,9 +480,15 @@ class LibraryController(
showCategories(false) showCategories(false)
} }
binding.categoryRecycler.onCategoryClicked = { binding.categoryRecycler.onCategoryClicked = {
binding.libraryGridRecycler.recycler.itemAnimator = null
scrollToHeader(it) 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 -> binding.categoryRecycler.onShowAllClicked = { isChecked ->
preferences.showAllCategories().set(isChecked) preferences.showAllCategories().set(isChecked)
@ -486,10 +509,12 @@ class LibraryController(
binding.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> { binding.fastScroller.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = binding.libraryGridRecycler.recycler.paddingTop topMargin = binding.libraryGridRecycler.recycler.paddingTop
} }
binding.headerTitle.updatePaddingRelative(top = insets.systemWindowInsetTop + 2.dpToPx) binding.headerCard.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.systemWindowInsetTop + 4.dpToPx
}
}, },
onLeavingController = { onLeavingController = {
binding.headerTitle.gone() binding.headerCard.gone()
}, },
onBottomNavUpdate = { onBottomNavUpdate = {
updateFilterSheetY() updateFilterSheetY()
@ -616,7 +641,7 @@ class LibraryController(
3 -> showGroupOptions() 3 -> showGroupOptions()
2 -> showDisplayOptions() 2 -> showDisplayOptions()
1 -> if (canCollapseOrExpandCategory() != null) presenter.toggleAllCategoryVisibility() 1 -> if (canCollapseOrExpandCategory() != null) presenter.toggleAllCategoryVisibility()
else -> activityBinding?.toolbar?.menu?.performIdentifierAction( else -> activityBinding?.cardToolbar?.menu?.performIdentifierAction(
R.id.action_search, R.id.action_search,
0 0
) )
@ -779,7 +804,12 @@ class LibraryController(
view.elevation = 15f.dpToPx view.elevation = 15f.dpToPx
setAction(R.string.cancel) { setAction(R.string.cancel) {
LibraryUpdateService.stop(context) 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() binding.progress.gone()
if (!freshStart) { if (!freshStart) {
justStarted = false 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() .start()
} else binding.recyclerLayout.alpha = 1f } else binding.recyclerLayout.alpha = 1f
if (justStarted && freshStart) { if (justStarted && freshStart) {
@ -942,6 +974,7 @@ class LibraryController(
showSlideAnimation() showSlideAnimation()
} }
} }
setSubtitle()
showMiniBar() showMiniBar()
} }
} }
@ -985,9 +1018,12 @@ class LibraryController(
.setDuration(duration) .setDuration(duration)
} }
private fun showCategories(show: Boolean) { private fun showCategories(show: Boolean, closeSearch: Boolean = false) {
binding.recyclerCover.isClickable = show binding.recyclerCover.isClickable = show
binding.recyclerCover.isFocusable = 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 full = binding.categoryRecycler.height.toFloat() + binding.libraryGridRecycler.recycler.paddingTop
val translateY = if (show) full else 0f val translateY = if (show) full else 0f
binding.libraryGridRecycler.recycler.animate().translationY(translateY).apply { binding.libraryGridRecycler.recycler.animate().translationY(translateY).apply {
@ -1002,7 +1038,7 @@ class LibraryController(
binding.libraryGridRecycler.recycler.suppressLayout(show) binding.libraryGridRecycler.recycler.suppressLayout(show)
activityBinding?.toolbar?.showDropdown(!show) activityBinding?.toolbar?.showDropdown(!show)
binding.swipeRefresh.isEnabled = !show binding.swipeRefresh.isEnabled = !show
setTitle() setSubtitle()
if (show) { if (show) {
binding.categoryRecycler.scrollToCategory(activeCategory) binding.categoryRecycler.scrollToCategory(activeCategory)
binding.fastScroller.hideScrollbar() binding.fastScroller.hideScrollbar()
@ -1075,7 +1111,10 @@ class LibraryController(
(binding.libraryGridRecycler.recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition() (binding.libraryGridRecycler.recycler.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
binding.libraryGridRecycler.recycler.adapter = adapter 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 { fun search(query: String?): Boolean {
@ -1085,7 +1124,9 @@ class LibraryController(
adapter.addScrollableHeader(searchItem) adapter.addScrollableHeader(searchItem)
} else if (this.query.isNotBlank()) { } else if (this.query.isNotBlank()) {
searchItem.string = this.query 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()) { } else if (this.query.isBlank() && adapter.scrollableHeaders.isNotEmpty()) {
adapter.removeAllScrollableHeaders() adapter.removeAllScrollableHeaders()
} }
@ -1264,7 +1305,10 @@ class LibraryController(
) || ) ||
adapter.getItem(fromPosition) == null 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 if (lastItemPosition == toPosition) lastItemPosition = null
else if (lastItemPosition == null) lastItemPosition = fromPosition else if (lastItemPosition == null) lastItemPosition = fromPosition
@ -1481,8 +1525,26 @@ class LibraryController(
searchView.clearFocus() searchView.clearFocus()
} }
setOnQueryTextChangeListener(searchView) { search(it) } setOnQueryTextChangeListener(searchView) {
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() }) 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 { override fun onOptionsItemSelected(item: MenuItem): Boolean {

View File

@ -12,6 +12,7 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.provider.Settings import android.provider.Settings
import android.view.GestureDetector import android.view.GestureDetector
import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
@ -21,6 +22,7 @@ import android.view.WindowManager
import android.webkit.WebView import android.webkit.WebView
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
@ -112,6 +114,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER private val isUpdaterEnabled = BuildConfig.INCLUDE_UPDATER
var tabAnimation: ValueAnimator? = null var tabAnimation: ValueAnimator? = null
var overflowDialog: Dialog? = null var overflowDialog: Dialog? = null
var currentToolbar: Toolbar? = null
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) { fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
this.snackBar = snackBar this.snackBar = snackBar
@ -145,7 +148,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
binding = MainActivityBinding.inflate(layoutInflater) binding = MainActivityBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.toolbar) setFloatingToolbar(true)
drawerArrow = DrawerArrowDrawable(this) drawerArrow = DrawerArrowDrawable(this)
drawerArrow?.color = getResourceColor(R.attr.actionBarTintColor) drawerArrow?.color = getResourceColor(R.attr.actionBarTintColor)
@ -270,6 +273,17 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} else onBackPressed() } 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.bottomNav.visibleIf(!hideBottomNav)
binding.bottomView.visibility = if (hideBottomNav) View.GONE else binding.bottomView.visibility binding.bottomView.visibility = if (hideBottomNav) View.GONE else binding.bottomView.visibility
binding.bottomNav.alpha = if (hideBottomNav) 0f else 1f binding.bottomNav.alpha = if (hideBottomNav) 0f else 1f
@ -325,12 +339,42 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
} }
preferences.incognitoMode() preferences.incognitoMode()
.asImmediateFlow { binding.toolbar.setIncognitoMode(it) } .asImmediateFlow {
binding.toolbar.setIncognitoMode(it)
binding.cardToolbar.setIncognitoMode(it)
}
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
setExtensionsBadge() 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) { fun setDismissIcon(enabled: Boolean) {
binding.cardToolbar.navigationIcon = if (enabled) dismissDrawable else searchDrawable
binding.toolbar.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) DownloadService.removeListener(this)
if (isBindingInitialized) { if (isBindingInitialized) {
binding.toolbar.setNavigationOnClickListener(null) 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())) 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 { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
// Initialize option to open catalogue settings. // Initialize option to open catalogue settings.
@ -660,6 +711,9 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
return super.dispatchTouchEvent(ev) return super.dispatchTouchEvent(ev)
} }
protected fun canShowFloatingToolbar(controller: Controller?) =
controller is FloatingSearchInterface
protected open fun syncActivityViewWithController( protected open fun syncActivityViewWithController(
to: Controller?, to: Controller?,
from: Controller? = null, from: Controller? = null,
@ -668,14 +722,18 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
if (from is DialogController || to is DialogController) { if (from is DialogController || to is DialogController) {
return return
} }
setFloatingToolbar(canShowFloatingToolbar(to))
val onRoot = router.backstackSize == 1 val onRoot = router.backstackSize == 1
if (onRoot) { if (onRoot) {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
binding.toolbar.navigationIcon = searchDrawable binding.toolbar.navigationIcon = searchDrawable
binding.cardToolbar.navigationIcon = searchDrawable
} else { } else {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
binding.toolbar.navigationIcon = drawerArrow binding.toolbar.navigationIcon = drawerArrow
binding.cardToolbar.navigationIcon = drawerArrow
} }
binding.cardToolbar.subtitle = null
drawerArrow?.progress = 1f drawerArrow?.progress = 1f
binding.bottomNav.visibility = if (!hideBottomNav) View.VISIBLE else binding.bottomNav.visibility binding.bottomNav.visibility = if (!hideBottomNav) View.VISIBLE else binding.bottomNav.visibility
@ -803,8 +861,19 @@ interface BottomNavBarInterface {
interface RootSearchInterface { interface RootSearchInterface {
fun expandSearch() { fun expandSearch() {
if (this is Controller) (activity as? MainActivity)?.binding?.toolbar?.menu?.findItem(R.id.action_search) if (this is Controller) {
?.expandActionView() 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.system.openInBrowser
import eu.kanade.tachiyomi.util.view.updateLayoutParams import eu.kanade.tachiyomi.util.view.updateLayoutParams
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.math.max
class OverflowDialog(activity: MainActivity) : Dialog(activity, R.style.OverflowDialogTheme) { 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> { 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?.let { window ->
window.navigationBarColor = Color.TRANSPARENT window.navigationBarColor = Color.TRANSPARENT

View File

@ -25,9 +25,9 @@ class SearchActivity : MainActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding.toolbar.navigationIcon = drawerArrow binding.toolbar.navigationIcon = drawerArrow
binding.toolbar.setNavigationOnClickListener { binding.cardToolbar.navigationIcon = drawerArrow
popToRoot() binding.toolbar.setNavigationOnClickListener { popToRoot() }
} binding.cardToolbar.setNavigationOnClickListener { popToRoot() }
(router.backstack.lastOrNull()?.controller() as? BaseController<*>)?.setTitle() (router.backstack.lastOrNull()?.controller() as? BaseController<*>)?.setTitle()
(router.backstack.lastOrNull()?.controller() as? SettingsController)?.setTitle() (router.backstack.lastOrNull()?.controller() as? SettingsController)?.setTitle()
} }
@ -63,6 +63,8 @@ class SearchActivity : MainActivity() {
if (from is DialogController || to is DialogController) { if (from is DialogController || to is DialogController) {
return return
} }
setFloatingToolbar(canShowFloatingToolbar(to))
binding.cardToolbar.navigationIcon = drawerArrow
binding.toolbar.navigationIcon = drawerArrow binding.toolbar.navigationIcon = drawerArrow
drawerArrow?.progress = 1f 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.controller.DialogController
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.ui.library.LibraryController 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.MainActivity
import eu.kanade.tachiyomi.ui.main.SearchActivity import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterHolder import eu.kanade.tachiyomi.ui.manga.chapter.ChapterHolder
@ -445,9 +446,10 @@ class MangaDetailsController :
if (router.backstackSize > 0 && if (router.backstackSize > 0 &&
router.backstack.last().controller() !is MangaDetailsController router.backstack.last().controller() !is MangaDetailsController
) { ) {
if (router.backstack.last().controller() !is FloatingSearchInterface) {
activityBinding?.appBar?.setBackgroundColor(colorSecondary) activityBinding?.appBar?.setBackgroundColor(colorSecondary)
}
activityBinding?.toolbar?.setBackgroundColor(colorSecondary) activityBinding?.toolbar?.setBackgroundColor(colorSecondary)
activity?.window?.statusBarColor = activity?.getResourceColor( activity?.window?.statusBarColor = activity?.getResourceColor(
android.R.attr.statusBarColor android.R.attr.statusBarColor
) ?: colorSecondary ) ?: 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.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.main.BottomSheetController 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.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
@ -74,6 +75,7 @@ class RecentsController(bundle: Bundle? = null) :
FlexibleAdapter.OnItemMoveListener, FlexibleAdapter.OnItemMoveListener,
FlexibleAdapter.EndlessScrollListener, FlexibleAdapter.EndlessScrollListener,
RootSearchInterface, RootSearchInterface,
FloatingSearchInterface,
BottomSheetController, BottomSheetController,
RemoveHistoryDialog.Listener { RemoveHistoryDialog.Listener {
@ -100,11 +102,16 @@ class RecentsController(bundle: Bundle? = null) :
private var lastChapterId: Long? = null private var lastChapterId: Long? = null
private var showingDownloads = false private var showingDownloads = false
var headerHeight = 0 var headerHeight = 0
private var query = ""
set(value) {
field = value
presenter.query = value
}
override fun getTitle(): String? { override fun getTitle(): String? {
return if (showingDownloads) { return if (showingDownloads) {
resources?.getString(R.string.download_queue) 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) override fun createBinding(inflater: LayoutInflater) = RecentsControllerBinding.inflate(inflater)
@ -230,7 +237,7 @@ class RecentsController(bundle: Bundle? = null) :
val oldShow = showingDownloads val oldShow = showingDownloads
showingDownloads = progress > 0.92f showingDownloads = progress > 0.92f
if (oldShow != showingDownloads) { if (oldShow != showingDownloads) {
setTitle() updateTitleAndMenu()
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
} }
@ -242,7 +249,7 @@ class RecentsController(bundle: Bundle? = null) :
binding.downloadBottomSheet.sheetLayout.alpha = binding.downloadBottomSheet.sheetLayout.alpha =
if (state == BottomSheetBehavior.STATE_COLLAPSED) 1f else 0f if (state == BottomSheetBehavior.STATE_COLLAPSED) 1f else 0f
showingDownloads = state == BottomSheetBehavior.STATE_EXPANDED showingDownloads = state == BottomSheetBehavior.STATE_EXPANDED
setTitle() updateTitleAndMenu()
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
} }
@ -299,6 +306,11 @@ class RecentsController(bundle: Bundle? = null) :
requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301) requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
} }
fun updateTitleAndMenu() {
(activity as? MainActivity)?.setFloatingToolbar(!showingDownloads, true)
setTitle()
}
private fun setBottomPadding() { private fun setBottomPadding() {
val bottomBar = activityBinding?.bottomNav ?: return val bottomBar = activityBinding?.bottomNav ?: return
val pad = bottomBar.translationY - bottomBar.height val pad = bottomBar.translationY - bottomBar.height
@ -554,7 +566,7 @@ class RecentsController(bundle: Bundle? = null) :
(activity as? MainActivity)?.setUndoSnackBar(snack) (activity as? MainActivity)?.setUndoSnackBar(snack)
} }
override fun isSearching() = presenter.query.isNotEmpty() override fun isSearching() = query.isNotEmpty()
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
if (onRoot) (activity as? MainActivity)?.setDismissIcon(showingDownloads) 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 searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView val searchView = searchItem.actionView as SearchView
searchView.queryHint = view?.context?.getString(R.string.search_recents) searchView.queryHint = view?.context?.getString(R.string.search_recents)
searchItem.collapseActionView()
if (isSearching()) { if (isSearching()) {
searchItem.expandActionView() searchItem.expandActionView()
searchView.setQuery(presenter.query, true) searchView.setQuery(query, true)
searchView.clearFocus() searchView.clearFocus()
} }
setOnQueryTextChangeListener(searchView) { setOnQueryTextChangeListener(searchView) {
if (presenter.query != it) { if (query != it) {
presenter.query = it ?: return@setOnQueryTextChangeListener false query = it ?: return@setOnQueryTextChangeListener false
// loadNoMore() // loadNoMore()
resetProgressItem() resetProgressItem()
refresh() refresh()
} }
true true
} }
searchItem.fixExpandInvalidate()
} }
} }
@ -636,7 +650,12 @@ class RecentsController(bundle: Bundle? = null) :
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) { override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeEnded(handler, type) 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() fun hasQueue() = presenter.downloadManager.hasQueue()
@ -659,7 +678,7 @@ class RecentsController(bundle: Bundle? = null) :
if (showingDownloads) { if (showingDownloads) {
binding.downloadBottomSheet.dlBottomSheet.dismiss() binding.downloadBottomSheet.dlBottomSheet.dismiss()
} else { } 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.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.controller.BaseController import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.util.view.scrollViewWith import eu.kanade.tachiyomi.util.view.scrollViewWith
import kotlinx.coroutines.MainScope import kotlinx.coroutines.MainScope
import rx.Observable import rx.Observable
@ -96,6 +97,9 @@ abstract class SettingsController : PreferenceController() {
} }
open fun getTitle(): String? { open fun getTitle(): String? {
if (this is FloatingSearchInterface) {
return searchTitle(preferenceScreen?.title?.toString())
}
return 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.Controller
import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.RouterTransaction
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchController import eu.kanade.tachiyomi.ui.setting.search.SettingsSearchController
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.util.view.withFadeTransaction
class SettingsMainController : SettingsController() { class SettingsMainController : SettingsController(), FloatingSearchInterface {
init { init {
setHasOptionsMenu(true) setHasOptionsMenu(true)

View File

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.SettingsSearchControllerBinding import eu.kanade.tachiyomi.databinding.SettingsSearchControllerBinding
import eu.kanade.tachiyomi.ui.base.controller.NucleusController 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.ui.setting.SettingsController
import eu.kanade.tachiyomi.util.view.liftAppbarWith import eu.kanade.tachiyomi.util.view.liftAppbarWith
import eu.kanade.tachiyomi.util.view.withFadeTransaction import eu.kanade.tachiyomi.util.view.withFadeTransaction
@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.util.view.withFadeTransaction
*/ */
class SettingsSearchController : class SettingsSearchController :
NucleusController<SettingsSearchControllerBinding, SettingsSearchPresenter>(), NucleusController<SettingsSearchControllerBinding, SettingsSearchPresenter>(),
FloatingSearchInterface,
SettingsSearchAdapter.OnTitleClickListener { SettingsSearchAdapter.OnTitleClickListener {
/** /**
@ -107,7 +109,7 @@ class SettingsSearchController :
adapter = SettingsSearchAdapter(this) adapter = SettingsSearchAdapter(this)
liftAppbarWith(binding.recycler) liftAppbarWith(binding.recycler, true)
// Create recycler and set adapter. // Create recycler and set adapter.
binding.recycler.layoutManager = LinearLayoutManager(view.context) binding.recycler.layoutManager = LinearLayoutManager(view.context)
binding.recycler.adapter = adapter 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.base.controller.BaseController
import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController import eu.kanade.tachiyomi.ui.extension.SettingsExtensionsController
import eu.kanade.tachiyomi.ui.main.BottomSheetController 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.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.setting.SettingsBrowseController 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.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.Date import java.util.Date
import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min
/** /**
* This controller shows and manages the different catalogues enabled by the user. * This controller shows and manages the different catalogues enabled by the user.
@ -73,6 +74,7 @@ class BrowseController :
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
SourceAdapter.SourceListener, SourceAdapter.SourceListener,
RootSearchInterface, RootSearchInterface,
FloatingSearchInterface,
BottomSheetController { BottomSheetController {
/** /**
@ -109,7 +111,7 @@ class BrowseController :
else -> R.string.source_migration else -> R.string.source_migration
} }
) )
} else view?.context?.getString(R.string.browse) } else searchTitle(view?.context?.getString(R.string.sources))
} }
val presenter = SourcePresenter(this) val presenter = SourcePresenter(this)
@ -142,19 +144,6 @@ class BrowseController :
bottom = (activityBinding?.bottomNav?.height ?: 0) + 58.spToPx 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 = { onBottomNavUpdate = {
setBottomPadding() setBottomPadding()
} }
@ -162,33 +151,31 @@ class BrowseController :
binding.sourceRecycler.post { binding.sourceRecycler.post {
setBottomSheetTabs(if (binding.bottomSheet.root.sheetBehavior.isCollapsed()) 0f else 1f) 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( binding.sourceRecycler.updatePaddingRelative(
bottom = (activityBinding?.bottomNav?.height ?: 0) + 58.spToPx 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) requestPermissionsSafe(arrayOf(WRITE_EXTERNAL_STORAGE), 301)
binding.bottomSheet.root.onCreate(this) 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( binding.bottomSheet.root.sheetBehavior?.addBottomSheetCallback(
object : BottomSheetBehavior object : BottomSheetBehavior
.BottomSheetCallback() { .BottomSheetCallback() {
override fun onSlide(bottomSheet: View, progress: Float) { override fun onSlide(bottomSheet: View, progress: Float) {
binding.shadow2.alpha = (1 - max(0f, progress)) * 0.25f binding.shadow2.alpha = (1 - max(0f, progress)) * 0.25f
activityBinding?.appBar?.elevation = min( binding.shadow.alpha = (1 - abs(progress)) * 0.5f
(1f - progress) * 15f,
if (binding.sourceRecycler.canScrollVertically(-1)) 15f else 0f
)
activityBinding?.appBar?.y = max(activityBinding!!.appBar.y, -headerHeight * (1 - progress)) activityBinding?.appBar?.y = max(activityBinding!!.appBar.y, -headerHeight * (1 - progress))
val oldShow = showingExtensions val oldShow = showingExtensions
showingExtensions = progress > 0.92f showingExtensions = progress > 0.92f
if (oldShow != showingExtensions) { if (oldShow != showingExtensions) {
setTitle() updateTitleAndMenu()
activity?.invalidateOptionsMenu()
} }
setBottomSheetTabs(max(0f, progress)) setBottomSheetTabs(max(0f, progress))
} }
@ -209,11 +196,15 @@ class BrowseController :
) { ) {
binding.bottomSheet.root.sheetBehavior?.isDraggable = true binding.bottomSheet.root.sheetBehavior?.isDraggable = true
showingExtensions = state == BottomSheetBehavior.STATE_EXPANDED showingExtensions = state == BottomSheetBehavior.STATE_EXPANDED
setTitle() updateTitleAndMenu()
if (state == BottomSheetBehavior.STATE_EXPANDED) { if (state == BottomSheetBehavior.STATE_EXPANDED) {
extBottomSheet.fetchOnlineExtensionsIfNeeded() extBottomSheet.fetchOnlineExtensionsIfNeeded()
} else extBottomSheet.shouldCallApi = true } 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) { retainViewMode = if (state == BottomSheetBehavior.STATE_EXPANDED) {
@ -238,8 +229,9 @@ class BrowseController :
} }
fun updateTitleAndMenu() { fun updateTitleAndMenu() {
setTitle() (activity as? MainActivity)?.setFloatingToolbar(!showingExtensions)
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
setTitle()
} }
fun setBottomSheetTabs(progress: Float) { fun setBottomSheetTabs(progress: Float) {
@ -348,20 +340,9 @@ class BrowseController :
} }
if (!type.isEnter) { if (!type.isEnter) {
binding.bottomSheet.root.canExpand = false binding.bottomSheet.root.canExpand = false
activityBinding?.appBar?.elevation =
when {
binding.bottomSheet.root.sheetBehavior.isExpanded() -> 0f
binding.sourceRecycler.canScrollVertically(-1) -> 15f
else -> 0f
}
} else { } else {
binding.bottomSheet.root.presenter.refreshMigrations() binding.bottomSheet.root.presenter.refreshMigrations()
activityBinding?.appBar?.elevation = updateTitleAndMenu()
when {
binding.bottomSheet.root.sheetBehavior.isExpanded() -> 0f
binding.sourceRecycler.canScrollVertically(-1) -> 15f
else -> 0f
}
} }
setBottomPadding() setBottomPadding()
} }
@ -458,7 +439,7 @@ class BrowseController :
override fun expandSearch() { override fun expandSearch() {
if (showingExtensions) binding.bottomSheet.root.sheetBehavior?.collapse() 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. // Change hint to show global search.
searchView.queryHint = view?.context?.getString(R.string.search_extensions) 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. // Create query listener which opens the global search view.
setOnQueryTextChangeListener(searchView) { setOnQueryTextChangeListener(searchView) {
extQuery = it ?: "" extQuery = it ?: ""
binding.bottomSheet.root.drawExtensions() binding.bottomSheet.root.drawExtensions()
true true
} }
searchItem.fixExpandInvalidate()
} else { } else {
inflater.inflate(R.menu.migration_main, menu) 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.model.FilterList
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController 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.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.source.BrowseController import eu.kanade.tachiyomi.ui.source.BrowseController
@ -57,6 +58,7 @@ open class BrowseSourceController(bundle: Bundle) :
NucleusController<BrowseSourceControllerBinding, BrowseSourcePresenter>(bundle), NucleusController<BrowseSourceControllerBinding, BrowseSourcePresenter>(bundle),
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener, FlexibleAdapter.OnItemLongClickListener,
FloatingSearchInterface,
FlexibleAdapter.EndlessScrollListener { FlexibleAdapter.EndlessScrollListener {
constructor( constructor(
@ -118,7 +120,7 @@ open class BrowseSourceController(bundle: Bundle) :
} }
override fun getTitle(): String? { override fun getTitle(): String? {
return presenter.source.name return searchTitle(presenter.source.name)
} }
override fun createPresenter(): BrowseSourcePresenter { 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.databinding.SourceGlobalSearchControllerBinding
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.ui.base.controller.NucleusController 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.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
@ -34,6 +35,7 @@ open class GlobalSearchController(
protected val initialQuery: String? = null, protected val initialQuery: String? = null,
protected val extensionFilter: String? = null protected val extensionFilter: String? = null
) : NucleusController<SourceGlobalSearchControllerBinding, GlobalSearchPresenter>(), ) : NucleusController<SourceGlobalSearchControllerBinding, GlobalSearchPresenter>(),
FloatingSearchInterface,
GlobalSearchCardAdapter.OnMangaClickListener { GlobalSearchCardAdapter.OnMangaClickListener {
/** /**

View File

@ -26,7 +26,9 @@ import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MainActivityBinding 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.BottomSheetController
import eu.kanade.tachiyomi.ui.main.FloatingSearchInterface
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
@ -67,15 +69,60 @@ fun Controller.setOnQueryTextChangeListener(
) )
} }
fun Controller.liftAppbarWith(recycler: RecyclerView) { 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() view?.applyWindowInsetsForController()
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
}
var elevationAnim: ValueAnimator? = null var elevationAnim: ValueAnimator? = null
var elevate = false var elevate = false
val elevateFunc: (Boolean) -> Unit = { el -> val elevateFunc: (Boolean) -> Unit = f@{ el ->
elevate = el elevate = el
elevationAnim?.cancel() elevationAnim?.cancel()
val floatingBar =
!(activityBinding?.toolbar?.isVisible == true || activityBinding?.tabsFrameLayout?.isVisible == true)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
return@f
}
elevationAnim = ValueAnimator.ofFloat( elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f, activityBinding?.appBar?.elevation ?: 0f,
if (el) 15f else 0f if (el) 15f else 0f
@ -85,6 +132,12 @@ fun Controller.liftAppbarWith(recycler: RecyclerView) {
} }
elevationAnim?.start() elevationAnim?.start()
} }
val floatingBar =
!(activityBinding?.toolbar?.isVisible == true || activityBinding?.tabsFrameLayout?.isVisible == true)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
}
elevateFunc(recycler.canScrollVertically(-1)) elevateFunc(recycler.canScrollVertically(-1))
recycler.addOnScrollListener( recycler.addOnScrollListener(
object : RecyclerView.OnScrollListener() { object : RecyclerView.OnScrollListener() {
@ -163,12 +216,21 @@ fun Controller.scrollViewWith(
var elevate = false var elevate = false
var isInView = true var isInView = true
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
val elevateFunc: (Boolean) -> Unit = { el -> val elevateFunc: (Boolean) -> Unit = f@{ el ->
elevate = el elevate = el
if (liftOnScroll != null) { if (liftOnScroll != null) {
liftOnScroll.invoke(el) liftOnScroll.invoke(el)
} else { } else {
elevationAnim?.cancel() elevationAnim?.cancel()
val floatingBar =
!(
activityBinding?.toolbar?.isVisible == true ||
(activityBinding?.tabsFrameLayout?.isVisible == true && includeTabView)
)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
return@f
}
elevationAnim = ValueAnimator.ofFloat( elevationAnim = ValueAnimator.ofFloat(
activityBinding?.appBar?.elevation ?: 0f, activityBinding?.appBar?.elevation ?: 0f,
if (el) 15f else 0f if (el) 15f else 0f
@ -179,6 +241,14 @@ fun Controller.scrollViewWith(
elevationAnim?.start() elevationAnim?.start()
} }
} }
val floatingBar =
!(
activityBinding?.toolbar?.isVisible == true ||
(activityBinding?.tabsFrameLayout?.isVisible == true && includeTabView)
)
if (floatingBar) {
activityBinding?.appBar?.elevation = 0f
}
addLifecycleListener( addLifecycleListener(
object : Controller.LifecycleListener() { object : Controller.LifecycleListener() {
override fun onChangeStart( override fun onChangeStart(
@ -211,8 +281,10 @@ fun Controller.scrollViewWith(
} }
} else { } else {
if (!customPadding && lastY == 0f && ( 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 val parent = recycler.parent as? ViewGroup ?: return

View File

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

View File

@ -54,6 +54,90 @@
tools:text="Title Text" /> tools:text="Title Text" />
</eu.kanade.tachiyomi.ui.base.CenteredToolbar> </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 <FrameLayout
android:id="@+id/tabs_frame_layout" android:id="@+id/tabs_frame_layout"
android:clickable="true" android:clickable="true"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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