Add chapters bottom sheet for reader

This commit is contained in:
Jobobby04 2020-08-22 17:26:03 -04:00
parent 4b12e977c0
commit 79e4e3d2a0
10 changed files with 565 additions and 87 deletions

View File

@ -26,6 +26,7 @@ import androidx.core.view.setPadding
import com.afollestad.materialdialogs.MaterialDialog
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.elvishew.xlog.XLog
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
@ -35,8 +36,10 @@ import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
import eu.kanade.tachiyomi.databinding.ReaderChaptersSheetBinding
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
@ -52,6 +55,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.GLUtil
import eu.kanade.tachiyomi.util.system.hasDisplayCutout
@ -63,7 +67,10 @@ import eu.kanade.tachiyomi.util.view.showBar
import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
import exh.util.collapse
import exh.util.defaultReaderType
import exh.util.hide
import exh.util.isExpanded
import java.io.File
import kotlin.math.abs
import kotlin.math.roundToLong
@ -120,6 +127,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
private val sourceManager: SourceManager by injectLazy()
private val logger = XLog.tag("ReaderActivity")
lateinit var readerBottomSheetBinding: ReaderChaptersSheetBinding
// SY <--
/**
@ -184,6 +193,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
// <-- EH
}
// SY -->
readerBottomSheetBinding = ReaderChaptersSheetBinding.bind(binding.readerChaptersSheet.root)
readerBottomSheetBinding.chaptersBottomSheet.setup(this)
// SY <--
config = ReaderConfig()
initializeMenu()
@ -229,6 +243,9 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
super.onDestroy()
viewer?.destroy()
viewer = null
// SY -->
readerBottomSheetBinding.chaptersBottomSheet.adapter = null
// SY <--
config = null
progressDialog?.dismiss()
progressDialog = null
@ -298,7 +315,14 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
presenter.bookmarkCurrentChapter(false)
invalidateOptionsMenu()
}
R.id.action_settings -> ReaderSettingsSheet(this).show()
R.id.action_settings -> {
ReaderSettingsSheet(this).show()
// SY -->
if (readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior.isExpanded()) {
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.collapse()
}
// SY <--
}
R.id.action_custom_filter -> {
val sheet = ReaderColorFilterSheet(this)
// Remove dimmed backdrop so changes can be previewed
@ -309,6 +333,11 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
setMenuVisibility(false)
sheet.show()
// SY -->
if (readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior.isExpanded()) {
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.collapse()
}
// SY <--
}
}
return super.onOptionsItemSelected(item)
@ -364,14 +393,15 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
}
// Init listeners on bottom menu
binding.pageSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
/* SY --> */readerBottomSheetBinding.pageSeekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() { /* SY <-- */
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
if (viewer != null && fromUser) {
moveToPageIndex(value)
}
}
})
binding.leftChapter.setOnClickListener {
/* SY --> binding.leftChapter.setOnClickListener {
if (viewer != null) {
if (viewer is R2LPagerViewer) {
loadNextChapter()
@ -388,7 +418,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
loadNextChapter()
}
}
}
} SY <-- */
// --> EH
binding.expandEhButton.clicks()
@ -544,6 +574,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
setMenuVisibility(menuVisible)
// --> EH
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.isHideable = !menuVisible
if (!menuVisible) readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.hide()
setEhUtilsVisibility(ehUtilsVisible)
// <-- EH
}
@ -586,8 +618,9 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
binding.header.startAnimation(toolbarAnimation)
// EXH <--
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
binding.readerMenuBottom.startAnimation(bottomAnimation)
// SY -->
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.collapse()
// SY <--
}
if (preferences.showPageNumber().get()) {
@ -611,8 +644,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
binding.header.startAnimation(toolbarAnimation)
// EXH <--
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
binding.readerMenuBottom.startAnimation(bottomAnimation)
// SY -->
BottomSheetBehavior.from(readerBottomSheetBinding.chaptersBottomSheet).isHideable = true
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.hide()
// SY <--
}
if (preferences.showPageNumber().get()) {
@ -621,6 +656,26 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
}
}
// SY -->
fun openMangaInBrowser() {
val source = sourceManager.getOrStub(presenter.manga!!.source) as? HttpSource ?: return
val url = try {
source.mangaDetailsRequest(presenter.manga!!).url.toString()
} catch (e: Exception) {
return
}
val intent = WebViewActivity.newIntent(
applicationContext, url, source.id, presenter.manga!!.title
)
startActivity(intent)
}
fun refreshSheetChapters() {
readerBottomSheetBinding.chaptersBottomSheet.refreshList()
}
// SY <--
/**
* Reset menu padding and system bar
*/
@ -662,7 +717,9 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
binding.toolbar.title = manga.title
binding.pageSeekbar.isRTL = newViewer is R2LPagerViewer
// SY -->
readerBottomSheetBinding.pageSeekbar.isRTL = newViewer is R2LPagerViewer
// SY <--
binding.pleaseWait.isVisible = true
binding.pleaseWait.startAnimation(AnimationUtils.loadAnimation(this, R.anim.fade_in_long))
@ -745,24 +802,25 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
*/
@SuppressLint("SetTextI18n")
fun onPageSelected(page: ReaderPage) {
presenter.onPageSelected(page)
val newChapter = presenter.onPageSelected(page)
val pages = page.chapter.pages ?: return
// Set bottom page number
binding.pageNumber.text = "${page.number}/${pages.size}"
// Set seekbar page number
if (viewer !is R2LPagerViewer) {
binding.leftPageText.text = "${page.number}"
binding.rightPageText.text = "${pages.size}"
} else {
binding.rightPageText.text = "${page.number}"
binding.leftPageText.text = "${pages.size}"
// SY -->
readerBottomSheetBinding.pageText.text = "${page.number}/${pages.size}"
if (!newChapter && readerBottomSheetBinding.chaptersBottomSheet.shouldCollapse && readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior.isExpanded()) {
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.collapse()
}
if (readerBottomSheetBinding.chaptersBottomSheet.selectedChapterId != page.chapter.chapter.id) {
readerBottomSheetBinding.chaptersBottomSheet.refreshList()
}
readerBottomSheetBinding.chaptersBottomSheet.shouldCollapse = true
// Set seekbar progress
binding.pageSeekbar.max = pages.lastIndex
binding.pageSeekbar.progress = page.index
readerBottomSheetBinding.pageSeekbar.max = pages.lastIndex
readerBottomSheetBinding.pageSeekbar.progress = page.index
// SY <--
}
/**
@ -778,6 +836,9 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
} catch (e: WindowManager.BadTokenException) {
logger.e("Caught and ignoring reader page sheet launch exception!", e)
}
if (readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior.isExpanded()) {
readerBottomSheetBinding.chaptersBottomSheet.sheetBehavior?.collapse()
}
// EXH <--
}

View File

@ -1,12 +1,14 @@
package eu.kanade.tachiyomi.ui.reader
import android.app.Application
import android.content.Context
import android.os.Bundle
import android.os.Environment
import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager
@ -16,6 +18,7 @@ import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterItem
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
@ -31,8 +34,12 @@ import exh.EH_SOURCE_ID
import exh.EXH_SOURCE_ID
import exh.util.defaultReaderType
import java.io.File
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import rx.Completable
import rx.Observable
import rx.Subscription
@ -250,6 +257,30 @@ class ReaderPresenter(
)
}
// SY -->
suspend fun getChapters(context: Context): List<ReaderChapterItem> {
return withContext(Dispatchers.IO) {
val currentChapter = getCurrentChapter()
val decimalFormat = DecimalFormat(
"#.###",
DecimalFormatSymbols()
.apply { decimalSeparator = '.' }
)
chapterList.reversed().map {
ReaderChapterItem(
it.chapter,
manga!!,
it.chapter == currentChapter?.chapter,
context,
preferences.dateFormat(),
decimalFormat
)
}
}
}
// SY <--
/**
* Returns an observable that loads the given [chapter] with this [loader]. This observable
* handles main thread synchronization and updating the currently active chapters on
@ -302,6 +333,11 @@ class ReaderPresenter(
.also(::add)
}
fun loadNewChapterFromSheet(chapter: Chapter) {
val newChapter = chapterList.firstOrNull { it.chapter.id == chapter.id } ?: return
loadAdjacent(newChapter)
}
/**
* Called when the user is going to load the prev/next chapter through the menu button. It
* sets the [isLoadingAdjacentChapterRelay] that the view uses to prevent any further
@ -353,8 +389,8 @@ class ReaderPresenter(
* read, update tracking services, enqueue downloaded chapter deletion, and updating the active chapter if this
* [page]'s chapter is different from the currently active.
*/
fun onPageSelected(page: ReaderPage) {
val currentChapters = viewerChaptersRelay.value ?: return
fun onPageSelected(page: ReaderPage): Boolean {
val currentChapters = viewerChaptersRelay.value ?: return /* SY --> */ false /* SY <-- */
val selectedChapter = page.chapter
@ -380,7 +416,14 @@ class ReaderPresenter(
Timber.d("Setting ${selectedChapter.chapter.url} as active")
onChapterChanged(currentChapters.currChapter)
loadNewChapter(selectedChapter)
// SY -->
Observable.just(selectedChapter).subscribeFirst({ view, _ ->
view.refreshSheetChapters()
})
return true
// SY <--
}
return /* SY --> */ false /* SY <-- */
}
/**
@ -472,6 +515,14 @@ class ReaderPresenter(
db.updateChapterProgress(chapter).executeAsBlocking()
}
// SY -->
fun toggleBookmark(chapter: Chapter) {
chapter.bookmark = !chapter.bookmark
db.updateChapterProgress(chapter).executeAsBlocking()
chapterList.firstOrNull { it.chapter.id == chapter.id }?.let { it.chapter.bookmark == !chapter.bookmark }
}
// SY <--
/**
* Returns the viewer position used by this manga or the default one.
*/

View File

@ -0,0 +1,104 @@
package eu.kanade.tachiyomi.ui.reader.chapter
import android.content.Context
import android.graphics.Typeface
import android.text.SpannableStringBuilder
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.items.AbstractItem
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.setVectorCompat
import java.text.DateFormat
import java.text.DecimalFormat
import java.util.Date
class ReaderChapterItem(val chapter: Chapter, val manga: Manga, val isCurrent: Boolean, context: Context, val dateFormat: DateFormat, val decimalFormat: DecimalFormat) :
AbstractItem<ReaderChapterItem.ViewHolder>(),
Chapter by chapter {
val readColor = context.getResourceColor(R.attr.colorOnSurface, 0.38f)
val unreadColor = context.getResourceColor(R.attr.colorOnSurface)
val bookmarkedColor = context.getResourceColor(R.attr.colorAccent)
/** defines the type defining this item. must be unique. preferably an id */
override val type: Int = R.id.reader_chapter_layout
/** defines the layout which will be used for this item in the list */
override val layoutRes: Int = R.layout.reader_chapter_item
override var identifier: Long = chapter.id!!
override fun getViewHolder(v: View): ViewHolder {
return ViewHolder(v)
}
class ViewHolder(view: View) : FastAdapter.ViewHolder<ReaderChapterItem>(view) {
private var chapterTitle: TextView = view.findViewById(R.id.chapter_title)
private var chapterSubtitle: TextView = view.findViewById(R.id.chapter_scanlator)
var bookmarkButton: FrameLayout = view.findViewById(R.id.bookmark_layout)
private var bookmarkImage: ImageView = view.findViewById(R.id.bookmark_image)
override fun bindView(item: ReaderChapterItem, payloads: List<Any>) {
val manga = item.manga
chapterTitle.text = when (manga.displayMode) {
Manga.DISPLAY_NUMBER -> {
val number = item.decimalFormat.format(item.chapter_number.toDouble())
itemView.context.getString(R.string.display_mode_chapter, number)
}
else -> item.name
}
// Set correct text color
val chapterColor = when {
item.read -> item.readColor
item.bookmark -> item.bookmarkedColor
else -> item.unreadColor
}
chapterTitle.setTextColor(chapterColor)
chapterSubtitle.setTextColor(chapterColor)
// bookmarkImage.isVisible = item.bookmark
val descriptions = mutableListOf<CharSequence>()
if (item.date_upload > 0) {
descriptions.add(item.dateFormat.format(Date(item.date_upload)))
}
if (!item.scanlator.isNullOrBlank()) {
descriptions.add(item.scanlator!!)
}
if (descriptions.isNotEmpty()) {
chapterSubtitle.text = descriptions.joinTo(SpannableStringBuilder(), "")
} else {
chapterSubtitle.text = ""
}
if (item.bookmark) {
bookmarkImage.setVectorCompat(R.drawable.ic_bookmark_24dp, R.attr.colorAccent)
} else {
bookmarkImage.setVectorCompat(R.drawable.ic_bookmark_border_24dp, R.attr.colorOnSurface)
}
if (item.isCurrent) {
chapterTitle.setTypeface(null, Typeface.BOLD_ITALIC)
chapterSubtitle.setTypeface(null, Typeface.BOLD_ITALIC)
} else {
chapterTitle.setTypeface(null, Typeface.NORMAL)
chapterSubtitle.setTypeface(null, Typeface.NORMAL)
}
}
override fun unbindView(item: ReaderChapterItem) {
chapterTitle.text = null
chapterSubtitle.text = null
}
}
}

View File

@ -0,0 +1,141 @@
package eu.kanade.tachiyomi.ui.reader.chapter
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.adapters.ItemAdapter
import com.mikepenz.fastadapter.listeners.ClickEventHook
import eu.kanade.tachiyomi.databinding.ReaderChaptersSheetBinding
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.dpToPx
import exh.util.collapse
import exh.util.expand
import exh.util.isExpanded
import kotlin.math.max
class ReaderChapterSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
LinearLayout(context, attrs) {
lateinit var binding: ReaderChaptersSheetBinding
var sheetBehavior: BottomSheetBehavior<View>? = null
lateinit var presenter: ReaderPresenter
var adapter: FastAdapter<ReaderChapterItem>? = null
private val itemAdapter = ItemAdapter<ReaderChapterItem>()
var shouldCollapse = true
var selectedChapterId = -1L
fun setup(activity: ReaderActivity) {
presenter = activity.presenter
binding = activity.readerBottomSheetBinding
sheetBehavior = BottomSheetBehavior.from(this)
binding.chaptersButton.setOnClickListener {
if (sheetBehavior.isExpanded()) {
sheetBehavior?.collapse()
} else {
sheetBehavior?.expand()
}
}
binding.webviewButton.setOnClickListener {
activity.openMangaInBrowser()
}
post {
binding.chapterRecycler.isClickable = sheetBehavior.isExpanded()
binding.chapterRecycler.isFocusable = sheetBehavior.isExpanded()
}
sheetBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, progress: Float) {
val trueProgress = max(progress, 0f)
binding.chaptersButton.alpha = 1 - trueProgress
binding.webviewButton.alpha = trueProgress
binding.webviewButton.isVisible = binding.webviewButton.alpha > 0
binding.chaptersButton.isInvisible = binding.chaptersButton.alpha <= 0
}
override fun onStateChanged(p0: View, state: Int) {
if (state == BottomSheetBehavior.STATE_COLLAPSED) {
shouldCollapse = true
sheetBehavior?.isHideable = false
(binding.chapterRecycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
adapter?.getPosition(presenter.getCurrentChapter()?.chapter?.id ?: 0L) ?: 0,
binding.chapterRecycler.height / 2 - 30.dpToPx
)
binding.chaptersButton.alpha = 1f
binding.webviewButton.alpha = 0f
}
if (state == BottomSheetBehavior.STATE_EXPANDED) {
binding.chaptersButton.alpha = 0f
binding.webviewButton.alpha = 1f
}
binding.chapterRecycler.isClickable = state == BottomSheetBehavior.STATE_EXPANDED
binding.chapterRecycler.isFocusable = state == BottomSheetBehavior.STATE_EXPANDED
binding.webviewButton.isVisible = state != BottomSheetBehavior.STATE_COLLAPSED
binding.chaptersButton.isInvisible = state == BottomSheetBehavior.STATE_EXPANDED
}
})
adapter = FastAdapter.with(itemAdapter)
binding.chapterRecycler.adapter = adapter
adapter?.onClickListener = { _, _, item, _ ->
if (!sheetBehavior.isExpanded()) {
false
} else {
if (item.chapter.id != presenter.getCurrentChapter()?.chapter?.id) {
shouldCollapse = false
presenter.loadNewChapterFromSheet(item.chapter)
}
true
}
}
adapter?.addEventHook(object : ClickEventHook<ReaderChapterItem>() {
override fun onBind(viewHolder: RecyclerView.ViewHolder): View? {
return if (viewHolder is ReaderChapterItem.ViewHolder) {
viewHolder.bookmarkButton
} else {
null
}
}
override fun onClick(
v: View,
position: Int,
fastAdapter: FastAdapter<ReaderChapterItem>,
item: ReaderChapterItem
) {
presenter.toggleBookmark(item.chapter)
refreshList()
}
})
binding.chapterRecycler.layoutManager = LinearLayoutManager(context)
refreshList()
}
fun refreshList() {
launchUI {
val chapters = presenter.getChapters(context)
selectedChapterId = chapters.find { it.isCurrent }?.chapter?.id ?: -1L
itemAdapter.clear()
itemAdapter.add(chapters)
(binding.chapterRecycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
adapter?.getPosition(presenter.getCurrentChapter()?.chapter?.id ?: 0L) ?: 0,
binding.chapterRecycler.height / 2 - 30.dpToPx
)
}
}
}

View File

@ -0,0 +1,22 @@
package exh.util
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
fun BottomSheetBehavior<*>.hide() {
state = STATE_HIDDEN
}
fun BottomSheetBehavior<*>.collapse() {
state = STATE_COLLAPSED
}
fun BottomSheetBehavior<*>.expand() {
state = STATE_EXPANDED
}
fun BottomSheetBehavior<*>?.isExpanded() = this?.state == STATE_EXPANDED
fun BottomSheetBehavior<*>?.isCollapsed() = this?.state == STATE_COLLAPSED
fun BottomSheetBehavior<*>?.isHidden() = this?.state == STATE_HIDDEN

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M2,17h2v0.5L3,17.5v1h1v0.5L2,19v1h3v-4L2,16v1zM3,8h1L4,4L2,4v1h1v3zM2,11h1.8L2,13.1v0.9h3v-1L3.2,13L5,10.9L5,10L2,10v1zM7,5v2h14L21,5L7,5zM7,19h14v-2L7,17v2zM7,13h14v-2L7,11v2z"/>
</vector>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -1,4 +1,4 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/reader_layout"
@ -151,73 +151,16 @@
app:srcCompat="@drawable/ic_keyboard_arrow_down_white_32dp" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:id="@+id/reader_menu_bottom"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:background="?attr/colorPrimary"
android:descendantFocusability="blocksDescendants"
android:gravity="center"
android:layoutDirection="ltr"
android:orientation="horizontal">
<ImageButton
android:id="@+id/left_chapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_previous_chapter"
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
app:srcCompat="@drawable/ic_skip_previous_24dp"
app:tint="?attr/colorOnPrimary" />
<TextView
android:id="@+id/left_page_text"
android:layout_width="32dp"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="15sp"
tools:text="1" />
<!--
Wonky way of setting height due to issues with horizontally centering the thumb in Android 5.
See https://stackoverflow.com/questions/15701767/android-thumb-is-not-centered-in-seekbar
-->
<eu.kanade.tachiyomi.ui.reader.ReaderSeekBar
android:id="@+id/page_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxHeight="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize" />
<TextView
android:id="@+id/right_page_text"
android:layout_width="32dp"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="15sp"
tools:text="15" />
<ImageButton
android:id="@+id/right_chapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_next_chapter"
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
app:srcCompat="@drawable/ic_skip_next_24dp"
app:tint="?attr/colorOnPrimary" />
</LinearLayout>
</FrameLayout>
<include
android:id="@+id/reader_chapters_sheet"
layout="@layout/reader_chapters_sheet" />
<View
android:id="@+id/brightness_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,64 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/reader_chapter_layout"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/list_item_selector"
android:backgroundTint="?attr/colorSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/chapter_title"
style="@style/TextAppearance.MaterialComponents.Body2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toTopOf="@id/chapter_scanlator"
app:layout_constraintEnd_toStartOf="@id/bookmark_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Chapter 123 - The Real One" />
<TextView
android:id="@+id/chapter_scanlator"
style="@style/TextAppearance.MaterialComponents.Caption"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="12dp"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/bookmark_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chapter_title"
tools:text="3 days ago • On page 45 • Scanlator" />
<FrameLayout
android:id="@+id/bookmark_layout"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginEnd="12dp"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_bookmark_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/bookmark_image"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center"
android:src="@drawable/ic_bookmark_border_24dp"
android:tint="?attr/colorOnSurface" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterSheet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/chapters_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="?attr/colorSurface"
android:orientation="vertical"
app:behavior_peekHeight="?attr/actionBarSize"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/topbar_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:clickable="true"
android:focusable="true">
<ImageView
android:id="@+id/pill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:contentDescription="@string/action_sort_drag_and_drop"
android:src="@drawable/ic_drag_pill_24dp"
android:tint="?attr/colorOnSurface"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/chapters_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_next_chapter"
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
android:tint="?attr/colorOnSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_format_list_numbered_24dp" />
<ImageButton
android:id="@+id/webview_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/action_open_in_web_view"
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
android:tint="?attr/colorOnSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:alpha="0.0"
app:srcCompat="@drawable/ic_public_24dp" />
<eu.kanade.tachiyomi.ui.reader.ReaderSeekBar
android:id="@+id/page_seekbar"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/page_text"
app:layout_constraintStart_toEndOf="@id/chapters_button"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/page_text"
android:layout_width="100dp"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="?attr/colorOnSurface"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="100 / 105" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chapter_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:clipToPadding="false"
tools:listitem="@layout/reader_chapter_item" />
</eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterSheet>