mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 19:55:11 +01:00
Added Chapter list to reader activity
Also using this as a test bed for fast adapter
This commit is contained in:
parent
472ba92fe6
commit
02896679fe
@ -186,6 +186,9 @@ dependencies {
|
|||||||
// UI
|
// UI
|
||||||
implementation("com.dmitrymalkovich.android:material-design-dimens:1.4")
|
implementation("com.dmitrymalkovich.android:material-design-dimens:1.4")
|
||||||
implementation("com.github.dmytrodanylyk.android-process-button:library:1.0.4")
|
implementation("com.github.dmytrodanylyk.android-process-button:library:1.0.4")
|
||||||
|
val latestFastAdapterRelease = "5.0.0"
|
||||||
|
implementation("com.mikepenz:fastadapter:${latestFastAdapterRelease}")
|
||||||
|
implementation("com.mikepenz:fastadapter-extensions-binding:${latestFastAdapterRelease}")
|
||||||
implementation("eu.davidea:flexible-adapter:5.1.0")
|
implementation("eu.davidea:flexible-adapter:5.1.0")
|
||||||
implementation("eu.davidea:flexible-adapter-ui:1.0.0")
|
implementation("eu.davidea:flexible-adapter-ui:1.0.0")
|
||||||
implementation("com.nononsenseapps:filepicker:2.5.2")
|
implementation("com.nononsenseapps:filepicker:2.5.2")
|
||||||
|
@ -71,7 +71,7 @@ class DisplayBottomSheet(private val controller: LibraryController) : BottomShee
|
|||||||
}
|
}
|
||||||
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
val isScrollable =
|
val isScrollable =
|
||||||
settings_scroll_view!!.height < bottom_sheet.height +
|
settings_scroll_view!!.height < display_layout.height +
|
||||||
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
||||||
close_button.visibleIf(isScrollable)
|
close_button.visibleIf(isScrollable)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class ChaptersSortBottomSheet(controller: MangaDetailsController) : BottomSheetD
|
|||||||
close_button.setOnClickListener { dismiss() }
|
close_button.setOnClickListener { dismiss() }
|
||||||
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
settings_scroll_view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
val isScrollable =
|
val isScrollable =
|
||||||
settings_scroll_view!!.height < bottom_sheet.height +
|
settings_scroll_view!!.height < sort_layout.height +
|
||||||
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
settings_scroll_view.paddingTop + settings_scroll_view.paddingBottom
|
||||||
close_button.visibleIf(isScrollable)
|
close_button.visibleIf(isScrollable)
|
||||||
pill.visibleIf(!isScrollable)
|
pill.visibleIf(!isScrollable)
|
||||||
|
@ -16,12 +16,14 @@ 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
|
||||||
|
import android.view.ViewGroup
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -50,12 +52,15 @@ import eu.kanade.tachiyomi.util.system.ThemeUtil
|
|||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||||
import eu.kanade.tachiyomi.util.view.gone
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
import eu.kanade.tachiyomi.widget.SimpleAnimationListener
|
||||||
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
|
||||||
import kotlinx.android.synthetic.main.reader_activity.*
|
import kotlinx.android.synthetic.main.reader_activity.*
|
||||||
|
import kotlinx.android.synthetic.main.reader_chapters_sheet.*
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import me.zhanghai.android.systemuihelper.SystemUiHelper
|
import me.zhanghai.android.systemuihelper.SystemUiHelper
|
||||||
@ -123,6 +128,8 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
*/
|
*/
|
||||||
private var bottomSheet: BottomSheetDialog? = null
|
private var bottomSheet: BottomSheetDialog? = null
|
||||||
|
|
||||||
|
var sheetManageNavColor = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Progress dialog used when switching chapters from the menu buttons.
|
* Progress dialog used when switching chapters from the menu buttons.
|
||||||
*/
|
*/
|
||||||
@ -181,6 +188,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
menuVisible = savedInstanceState.getBoolean(::menuVisible.name)
|
menuVisible = savedInstanceState.getBoolean(::menuVisible.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chapters_bottom_sheet.setup(this)
|
||||||
config = ReaderConfig()
|
config = ReaderConfig()
|
||||||
initializeMenu()
|
initializeMenu()
|
||||||
}
|
}
|
||||||
@ -191,6 +199,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
viewer?.destroy()
|
viewer?.destroy()
|
||||||
|
chapters_bottom_sheet.adapter = null
|
||||||
viewer = null
|
viewer = null
|
||||||
config?.destroy()
|
config?.destroy()
|
||||||
config = null
|
config = null
|
||||||
@ -248,6 +257,9 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
bottomSheet?.show()
|
bottomSheet?.show()
|
||||||
|
if (chapters_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
chapters_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,6 +268,10 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
* delegated to the presenter.
|
* delegated to the presenter.
|
||||||
*/
|
*/
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
|
if (chapters_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
chapters_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
return
|
||||||
|
}
|
||||||
presenter.onBackPressed()
|
presenter.onBackPressed()
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
@ -288,6 +304,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
onBackPressed()
|
onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BottomSheetBehavior.from(chapters_bottom_sheet).isHideable = true
|
||||||
// Init listeners on bottom menu
|
// Init listeners on bottom menu
|
||||||
page_seekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
page_seekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||||
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekBar: SeekBar, value: Int, fromUser: Boolean) {
|
||||||
@ -296,27 +313,35 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
left_chapter.setOnClickListener {
|
|
||||||
if (viewer != null) {
|
|
||||||
if (viewer is R2LPagerViewer)
|
|
||||||
loadNextChapter()
|
|
||||||
else
|
|
||||||
loadPreviousChapter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
right_chapter.setOnClickListener {
|
|
||||||
if (viewer != null) {
|
|
||||||
if (viewer is R2LPagerViewer)
|
|
||||||
loadPreviousChapter()
|
|
||||||
else
|
|
||||||
loadNextChapter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial visibility
|
// Set initial visibility
|
||||||
setMenuVisibility(menuVisible)
|
setMenuVisibility(menuVisible)
|
||||||
if (!menuVisible)
|
if (!menuVisible)
|
||||||
reader_menu_bottom.visibility = View.GONE
|
chapters_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_HIDDEN
|
||||||
|
reader_menu.doOnApplyWindowInsets { v, insets, _ ->
|
||||||
|
sheetManageNavColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && (insets
|
||||||
|
.systemWindowInsetBottom != insets.tappableElementInsets.bottom)) {
|
||||||
|
window.navigationBarColor = Color.TRANSPARENT
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// if in landscape with 2/3 button mode, fully opaque nav bar
|
||||||
|
else if (insets.systemWindowInsetLeft > 0 || insets.systemWindowInsetRight > 0) {
|
||||||
|
window.navigationBarColor = getResourceColor(R.attr.colorPrimary)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
// if in portrait with 2/3 button mode, translucent nav bar
|
||||||
|
else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
topMargin = insets.systemWindowInsetTop
|
||||||
|
}
|
||||||
|
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
leftMargin = insets.systemWindowInsetLeft
|
||||||
|
rightMargin = insets.systemWindowInsetRight
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -330,10 +355,10 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
snackbar?.dismiss()
|
snackbar?.dismiss()
|
||||||
systemUi?.show()
|
systemUi?.show()
|
||||||
reader_menu.visibility = View.VISIBLE
|
reader_menu.visibility = View.VISIBLE
|
||||||
reader_menu_bottom.visibility = View.VISIBLE
|
if (chapters_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
chapters_bottom_sheet.sheetBehavior?.isHideable = false
|
||||||
window.navigationBarColor = getResourceColor(R.attr.colorPrimaryDark)
|
if (chapters_bottom_sheet.sheetBehavior?.state != BottomSheetBehavior.STATE_EXPANDED && sheetManageNavColor)
|
||||||
}
|
window.navigationBarColor = Color.TRANSPARENT // getResourceColor(R.attr.colorPrimaryDark)
|
||||||
if (animate) {
|
if (animate) {
|
||||||
if (!menuStickyVisible) {
|
if (!menuStickyVisible) {
|
||||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
||||||
@ -344,8 +369,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
})
|
})
|
||||||
toolbar.startAnimation(toolbarAnimation)
|
toolbar.startAnimation(toolbarAnimation)
|
||||||
}
|
}
|
||||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
|
BottomSheetBehavior.from(chapters_bottom_sheet).state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
reader_menu_bottom.startAnimation(bottomAnimation)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
systemUi?.hide()
|
systemUi?.hide()
|
||||||
@ -358,10 +382,8 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
toolbar.startAnimation(toolbarAnimation)
|
toolbar.startAnimation(toolbarAnimation)
|
||||||
if (reader_menu_bottom.visibility != View.GONE) {
|
BottomSheetBehavior.from(chapters_bottom_sheet).isHideable = true
|
||||||
val bottomAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
|
BottomSheetBehavior.from(chapters_bottom_sheet).state = BottomSheetBehavior.STATE_HIDDEN
|
||||||
reader_menu_bottom.startAnimation(bottomAnimation)
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
reader_menu.visibility = View.GONE
|
reader_menu.visibility = View.GONE
|
||||||
}
|
}
|
||||||
@ -465,20 +487,8 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
viewer.moveToPage(page)
|
viewer.moveToPage(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun refreshChapters() {
|
||||||
* Tells the presenter to load the next chapter and mark it as active. The progress dialog
|
chapters_bottom_sheet.refreshList()
|
||||||
* should be automatically shown.
|
|
||||||
*/
|
|
||||||
private fun loadNextChapter() {
|
|
||||||
presenter.loadNextChapter()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the presenter to load the previous chapter and mark it as active. The progress dialog
|
|
||||||
* should be automatically shown.
|
|
||||||
*/
|
|
||||||
private fun loadPreviousChapter() {
|
|
||||||
presenter.loadPreviousChapter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -492,19 +502,17 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
|
|
||||||
// Set bottom page number
|
// Set bottom page number
|
||||||
page_number.text = "${page.number}/${pages.size}"
|
page_number.text = "${page.number}/${pages.size}"
|
||||||
|
|
||||||
// Set seekbar page number
|
// Set seekbar page number
|
||||||
if (viewer !is R2LPagerViewer) {
|
page_text.text = "${page.number} / ${pages.size}"
|
||||||
left_page_text.text = "${page.number}"
|
|
||||||
right_page_text.text = "${pages.size}"
|
|
||||||
} else {
|
|
||||||
right_page_text.text = "${page.number}"
|
|
||||||
left_page_text.text = "${pages.size}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newChapter && config?.showNewChapter == false) {
|
if (newChapter) {
|
||||||
systemUi?.show()
|
if (config?.showNewChapter == false) systemUi?.show()
|
||||||
|
} else if (chapters_bottom_sheet.shouldCollaspe && chapters_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
chapters_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
}
|
}
|
||||||
|
if (chapters_bottom_sheet.selectedChapterId != presenter.getCurrentChapter()?.chapter?.id)
|
||||||
|
chapters_bottom_sheet.refreshList()
|
||||||
|
chapters_bottom_sheet.shouldCollaspe = true
|
||||||
|
|
||||||
// Set seekbar progress
|
// Set seekbar progress
|
||||||
page_seekbar.max = pages.lastIndex
|
page_seekbar.max = pages.lastIndex
|
||||||
@ -517,6 +525,9 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
*/
|
*/
|
||||||
fun onPageLongTap(page: ReaderPage) {
|
fun onPageLongTap(page: ReaderPage) {
|
||||||
ReaderPageSheet(this, page).show()
|
ReaderPageSheet(this, page).show()
|
||||||
|
if (chapters_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
chapters_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -621,10 +632,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
setMenuVisibility(false)
|
setMenuVisibility(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
if (sheetManageNavColor) window.navigationBarColor = getResourceColor(R.attr.colorPrimary)
|
||||||
window.navigationBarColor = getColor(android.R.color.transparent)
|
|
||||||
}
|
|
||||||
reader_menu_bottom.visibility = View.GONE
|
|
||||||
reader_menu.visibility = View.VISIBLE
|
reader_menu.visibility = View.VISIBLE
|
||||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
||||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
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 kotlinx.android.synthetic.main.chapters_item.*
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
import java.text.DecimalFormatSymbols
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
class ReaderChapterItem(val chapter: Chapter, val manga: Manga, val isCurrent: Boolean) :
|
||||||
|
AbstractItem<ReaderChapterItem.ViewHolder>
|
||||||
|
() {
|
||||||
|
|
||||||
|
var name: String? = null
|
||||||
|
var description: String? = null
|
||||||
|
val decimalFormat =
|
||||||
|
DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
|
||||||
|
|
||||||
|
/** defines the type defining this item. must be unique. preferably an id */
|
||||||
|
override val type: Int
|
||||||
|
get() = R.id.reader_chapter_layout
|
||||||
|
|
||||||
|
/** defines the layout which will be used for this item in the list */
|
||||||
|
override val layoutRes: Int
|
||||||
|
get() = R.layout.reader_chapter_item
|
||||||
|
|
||||||
|
override var identifier: Long
|
||||||
|
get() = chapter.id!!
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
override fun getViewHolder(v: View): ViewHolder {
|
||||||
|
return ViewHolder(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViewHolder(view: View) : FastAdapter.ViewHolder<ReaderChapterItem>(view) {
|
||||||
|
var chapterTitle: TextView = view.findViewById(R.id.chapter_title)
|
||||||
|
var chapterSubtitle: TextView = view.findViewById(R.id.chapter_scanlator)
|
||||||
|
var bookmarkButton: FrameLayout = view.findViewById(R.id.bookmark_layout)
|
||||||
|
var bookmarkImage: ImageView = view.findViewById(R.id.bookmark_image)
|
||||||
|
|
||||||
|
private var readColor = view.context.getResourceColor(android.R.attr.textColorHint)
|
||||||
|
private var unreadColor = view.context.getResourceColor(android.R.attr.textColorPrimary)
|
||||||
|
private var activeColor = view.context.getResourceColor(android.R.attr.colorAccent)
|
||||||
|
|
||||||
|
private var unbookmark = ContextCompat.getDrawable(view.context, R.drawable
|
||||||
|
.ic_bookmark_border_24dp)
|
||||||
|
private var bookmark = ContextCompat.getDrawable(view.context, R.drawable
|
||||||
|
.ic_bookmark_24dp)
|
||||||
|
|
||||||
|
override fun bindView(item: ReaderChapterItem, payloads: List<Any>) {
|
||||||
|
val chapter = item.chapter
|
||||||
|
val manga = item.manga
|
||||||
|
chapterTitle.text = when (manga.displayMode) {
|
||||||
|
Manga.DISPLAY_NUMBER -> {
|
||||||
|
val number = item.decimalFormat.format(chapter.chapter_number.toDouble())
|
||||||
|
itemView.context.getString(R.string.chapter_, number)
|
||||||
|
}
|
||||||
|
else -> chapter.name
|
||||||
|
}
|
||||||
|
val statuses = mutableListOf<String>()
|
||||||
|
if (chapter.date_upload > 0) {
|
||||||
|
statuses.add(
|
||||||
|
DateUtils.getRelativeTimeSpanString(
|
||||||
|
chapter.date_upload, Date().time, DateUtils.HOUR_IN_MILLIS
|
||||||
|
).toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chapter.scanlator.isNullOrBlank()) {
|
||||||
|
statuses.add(chapter.scanlator!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
chapterTitle.setTextColor(
|
||||||
|
when {
|
||||||
|
item.isCurrent -> activeColor
|
||||||
|
chapter.read -> readColor
|
||||||
|
else -> unreadColor
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
chapterSubtitle.setTextColor(
|
||||||
|
when {
|
||||||
|
item.isCurrent -> activeColor
|
||||||
|
chapter.read -> readColor
|
||||||
|
else -> unreadColor
|
||||||
|
}
|
||||||
|
)
|
||||||
|
bookmarkImage.setImageDrawable(if (chapter.bookmark)
|
||||||
|
bookmark
|
||||||
|
else unbookmark)
|
||||||
|
bookmarkImage.imageTintList = ColorStateList.valueOf(if (chapter.bookmark)
|
||||||
|
activeColor
|
||||||
|
else readColor)
|
||||||
|
chapterSubtitle.text = statuses.joinToString(" • ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unbindView(item: ReaderChapterItem) {
|
||||||
|
chapterTitle.text = null
|
||||||
|
chapterSubtitle.text = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
|
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.R
|
||||||
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
|
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||||
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
|
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||||
|
import kotlinx.android.synthetic.main.reader_chapters_sheet.view.*
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
class ReaderChapterSheet @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
|
LinearLayout(context, attrs) {
|
||||||
|
|
||||||
|
var sheetBehavior: BottomSheetBehavior<View>? = null
|
||||||
|
lateinit var presenter: ReaderPresenter
|
||||||
|
var adapter: FastAdapter<ReaderChapterItem>? = null
|
||||||
|
private val itemAdapter = ItemAdapter<ReaderChapterItem>()
|
||||||
|
var shouldCollaspe = true
|
||||||
|
var selectedChapterId = -1L
|
||||||
|
|
||||||
|
fun setup(activity: ReaderActivity) {
|
||||||
|
presenter = activity.presenter
|
||||||
|
val primary = activity.getResourceColor(R.attr.colorPrimary)
|
||||||
|
val fullPrimary = ContextCompat.getColor(activity, R.color.darkPrimaryColor)
|
||||||
|
sheetBehavior = BottomSheetBehavior.from(this)
|
||||||
|
chapters_button.setOnClickListener {
|
||||||
|
if (sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) sheetBehavior?.state =
|
||||||
|
BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
else sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
|
val peek = sheetBehavior?.peekHeight ?: 30.dpToPx
|
||||||
|
post {
|
||||||
|
chapter_recycler.alpha =
|
||||||
|
if (sheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) 1f else 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
chapters_bottom_sheet.doOnApplyWindowInsets { _, insets, _ ->
|
||||||
|
sheetBehavior?.peekHeight =
|
||||||
|
peek + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) insets.mandatorySystemGestureInsets.bottom
|
||||||
|
else insets.systemWindowInsetBottom
|
||||||
|
chapters_bottom_sheet.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
height = 280.dpToPx + insets.systemWindowInsetBottom
|
||||||
|
}
|
||||||
|
chapter_recycler.updatePaddingRelative(bottom = insets.systemWindowInsetBottom)
|
||||||
|
}
|
||||||
|
sheetBehavior?.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
|
||||||
|
override fun onSlide(bottomSheet: View, progress: Float) {
|
||||||
|
val trueProgress = max(progress, 0f)
|
||||||
|
backgroundTintList = ColorStateList.valueOf(lerpColor(primary, fullPrimary, trueProgress))
|
||||||
|
chapter_recycler.alpha = trueProgress
|
||||||
|
if (activity.sheetManageNavColor) activity.window.navigationBarColor =
|
||||||
|
lerpColor(ColorUtils.setAlphaComponent(primary, 0), primary, trueProgress)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStateChanged(p0: View, state: Int) {
|
||||||
|
if (state == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||||
|
shouldCollaspe = true
|
||||||
|
sheetBehavior?.isHideable = false
|
||||||
|
(chapter_recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
||||||
|
adapter?.getPosition(presenter.getCurrentChapter()?.chapter?.id ?: 0L) ?: 0,
|
||||||
|
chapter_recycler.height / 2 - 30.dpToPx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
chapter_recycler.alpha = 1f
|
||||||
|
if (activity.sheetManageNavColor) activity.window.navigationBarColor = primary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
adapter = FastAdapter.with(itemAdapter)
|
||||||
|
chapter_recycler.adapter = adapter
|
||||||
|
adapter?.onClickListener = { _, _, item, _ ->
|
||||||
|
if (item.chapter.id != presenter.getCurrentChapter()?.chapter?.id) {
|
||||||
|
shouldCollaspe = false
|
||||||
|
presenter.loadChapter(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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
chapter_recycler.layoutManager = LinearLayoutManager(context)
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshList() {
|
||||||
|
launchUI {
|
||||||
|
val chapters = presenter.getChapters()
|
||||||
|
|
||||||
|
selectedChapterId = chapters.find { it.isCurrent }?.chapter?.id ?: -1L
|
||||||
|
itemAdapter.clear()
|
||||||
|
itemAdapter.add(chapters)
|
||||||
|
|
||||||
|
(chapter_recycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
|
||||||
|
adapter?.getPosition(presenter.getCurrentChapter()?.chapter?.id ?: 0L) ?: 0,
|
||||||
|
chapter_recycler.height / 2 - 30.dpToPx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lerpColor(colorStart: Int, colorEnd: Int, percent: Float): Int {
|
||||||
|
val perc = (percent * 100).roundToInt()
|
||||||
|
return Color.argb(
|
||||||
|
lerpColorCalc(Color.alpha(colorStart), Color.alpha(colorEnd), perc),
|
||||||
|
lerpColorCalc(Color.red(colorStart), Color.red(colorEnd), perc),
|
||||||
|
lerpColorCalc(Color.green(colorStart), Color.green(colorEnd), perc),
|
||||||
|
lerpColorCalc(Color.blue(colorStart), Color.blue(colorEnd), perc)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun lerpColorCalc(colorStart: Int, colorEnd: Int, percent: Int): Int {
|
||||||
|
return (min(colorStart, colorEnd) * (100 - percent) + max(
|
||||||
|
colorStart, colorEnd
|
||||||
|
) * percent) / 100
|
||||||
|
}
|
||||||
|
}
|
@ -7,11 +7,13 @@ import com.jakewharton.rxrelay.BehaviorRelay
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
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.History
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
@ -24,8 +26,11 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
|||||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.executeOnIO
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
@ -51,6 +56,8 @@ class ReaderPresenter(
|
|||||||
private val preferences: PreferencesHelper = Injekt.get()
|
private val preferences: PreferencesHelper = Injekt.get()
|
||||||
) : BasePresenter<ReaderActivity>() {
|
) : BasePresenter<ReaderActivity>() {
|
||||||
|
|
||||||
|
private var scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manga loaded in the reader. It can be null when instantiated for a short time.
|
* The manga loaded in the reader. It can be null when instantiated for a short time.
|
||||||
*/
|
*/
|
||||||
@ -112,6 +119,8 @@ class ReaderPresenter(
|
|||||||
}.map(::ReaderChapter)
|
}.map(::ReaderChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chapterItems = emptyList<ReaderChapterItem>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the presenter is created. It retrieves the saved active chapter if the process
|
* Called when the presenter is created. It retrieves the saved active chapter if the process
|
||||||
* was restored.
|
* was restored.
|
||||||
@ -182,6 +191,25 @@ class ReaderPresenter(
|
|||||||
}, ReaderActivity::setInitialChapterError)
|
}, ReaderActivity::setInitialChapterError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getChapters(): List<ReaderChapterItem> {
|
||||||
|
val manga = manga ?: return emptyList()
|
||||||
|
chapterItems = withContext(Dispatchers.IO) {
|
||||||
|
val list = db.getChapters(manga).executeOnIO().sortedBy {
|
||||||
|
when (manga.sorting) {
|
||||||
|
Manga.SORTING_NUMBER -> it.chapter_number
|
||||||
|
else -> it.source_order.toFloat()
|
||||||
|
}
|
||||||
|
}.map {
|
||||||
|
ReaderChapterItem(it, manga, it.id ==
|
||||||
|
getCurrentChapter()?.chapter?.id ?: chapterId)
|
||||||
|
}
|
||||||
|
if (!manga.sortDescending(preferences.chaptersDescAsDefault().getOrDefault()))
|
||||||
|
list.reversed()
|
||||||
|
else list
|
||||||
|
}
|
||||||
|
return chapterItems
|
||||||
|
}
|
||||||
|
|
||||||
fun init(mangaId: Long, chapterUrl: String) {
|
fun init(mangaId: Long, chapterUrl: String) {
|
||||||
if (!needsInit()) return
|
if (!needsInit()) return
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
@ -270,27 +298,28 @@ class ReaderPresenter(
|
|||||||
.also(::add)
|
.also(::add)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun loadChapter(chapter: Chapter) {
|
||||||
* 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
|
|
||||||
* interaction until the chapter is loaded.
|
|
||||||
*/
|
|
||||||
private fun loadAdjacent(chapter: ReaderChapter) {
|
|
||||||
val loader = loader ?: return
|
val loader = loader ?: return
|
||||||
|
|
||||||
Timber.d("Loading adjacent ${chapter.chapter.url}")
|
Timber.d("Loading adjacent ${chapter.url}")
|
||||||
|
|
||||||
activeChapterSubscription?.unsubscribe()
|
activeChapterSubscription?.unsubscribe()
|
||||||
activeChapterSubscription = getLoadObservable(loader, chapter)
|
activeChapterSubscription = getLoadObservable(loader, ReaderChapter(chapter))
|
||||||
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
|
.doOnSubscribe { isLoadingAdjacentChapterRelay.call(true) }
|
||||||
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
|
.doOnUnsubscribe { isLoadingAdjacentChapterRelay.call(false) }
|
||||||
.subscribeFirst({ view, _ ->
|
.subscribeFirst({ view, _ ->
|
||||||
view.moveToPageIndex(0)
|
view.moveToPageIndex(0)
|
||||||
|
view.refreshChapters()
|
||||||
}, { _, _ ->
|
}, { _, _ ->
|
||||||
// Ignore onError event, viewers handle that state
|
// Ignore onError event, viewers handle that state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleBookmark(chapter: Chapter) {
|
||||||
|
chapter.bookmark = !chapter.bookmark
|
||||||
|
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the viewers decide it's a good time to preload a [chapter] and improve the UX so
|
* Called when the viewers decide it's a good time to preload a [chapter] and improve the UX so
|
||||||
* that the user doesn't have to wait too long to continue reading.
|
* that the user doesn't have to wait too long to continue reading.
|
||||||
@ -355,6 +384,8 @@ class ReaderPresenter(
|
|||||||
* Saves this [chapter] progress (last read page and whether it's read).
|
* Saves this [chapter] progress (last read page and whether it's read).
|
||||||
*/
|
*/
|
||||||
private fun saveChapterProgress(chapter: ReaderChapter) {
|
private fun saveChapterProgress(chapter: ReaderChapter) {
|
||||||
|
val dbChapter = db.getChapter(chapter.chapter.id!!).executeAsBlocking()
|
||||||
|
chapter.chapter.bookmark = dbChapter!!.bookmark
|
||||||
db.updateChapterProgress(chapter.chapter).asRxCompletable()
|
db.updateChapterProgress(chapter.chapter).asRxCompletable()
|
||||||
.onErrorComplete()
|
.onErrorComplete()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
@ -376,22 +407,6 @@ class ReaderPresenter(
|
|||||||
preload(chapter)
|
preload(chapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from the activity to load and set the next chapter as active.
|
|
||||||
*/
|
|
||||||
fun loadNextChapter() {
|
|
||||||
val nextChapter = viewerChaptersRelay.value?.nextChapter ?: return
|
|
||||||
loadAdjacent(nextChapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from the activity to load and set the previous chapter as active.
|
|
||||||
*/
|
|
||||||
fun loadPreviousChapter() {
|
|
||||||
val prevChapter = viewerChaptersRelay.value?.prevChapter ?: return
|
|
||||||
loadAdjacent(prevChapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently active chapter.
|
* Returns the currently active chapter.
|
||||||
*/
|
*/
|
||||||
|
8
app/src/main/res/drawable/bg_bottom_sheet_black.xml
Normal file
8
app/src/main/res/drawable/bg_bottom_sheet_black.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="14dp"
|
||||||
|
android:topRightRadius="14dp" />
|
||||||
|
<solid android:color="@android:color/black" />
|
||||||
|
</shape>
|
5
app/src/main/res/drawable/ic_bookmark_border_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_bookmark_border_24dp.xml
Normal 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="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z"/>
|
||||||
|
</vector>
|
@ -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>
|
32
app/src/main/res/drawable/oval_ripple.xml
Normal file
32
app/src/main/res/drawable/oval_ripple.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:color="@color/colorAccent">
|
||||||
|
<item android:id="@android:id/mask">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/colorAccent" />
|
||||||
|
<corners android:radius="30dp" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<selector>
|
||||||
|
<item android:state_activated="false">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
<size
|
||||||
|
android:width="32dp"
|
||||||
|
android:height="32dp" />
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_activated="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
<size
|
||||||
|
android:width="32dp"
|
||||||
|
android:height="32dp" />
|
||||||
|
<solid android:color="@color/colorAccent" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
</item>
|
||||||
|
</ripple>
|
@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:color="@color/colorAccent">
|
android:color="@color/gray_button">
|
||||||
<item android:id="@android:id/mask">
|
<item android:id="@android:id/mask">
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="@color/colorAccent" />
|
<solid android:color="@color/gray_button" />
|
||||||
<corners android:radius="16dp" />
|
<corners android:radius="30dp" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<size
|
<size
|
||||||
android:width="32dp"
|
android:width="32dp"
|
||||||
android:height="32dp" />
|
android:height="32dp" />
|
||||||
<solid android:color="@color/colorAccent" />
|
<solid android:color="@color/gray_button" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
</selector>
|
</selector>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/bottom_sheet"
|
android:id="@+id/sort_layout"
|
||||||
style="@style/BottomSheetDialogTheme"
|
style="@style/BottomSheetDialogTheme"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/bottom_sheet"
|
android:id="@+id/display_layout"
|
||||||
style="@style/BottomSheetDialogTheme"
|
style="@style/BottomSheetDialogTheme"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:background="@drawable/rounded_ripple"
|
android:background="@drawable/oval_ripple"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
@ -35,7 +35,7 @@
|
|||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:background="@drawable/rounded_ripple"
|
android:background="@drawable/oval_ripple"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
@ -57,7 +57,7 @@
|
|||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
android:background="@drawable/rounded_ripple"
|
android:background="@drawable/oval_ripple"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:textStyle="normal"
|
android:textStyle="normal"
|
||||||
|
@ -34,11 +34,10 @@
|
|||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:id="@+id/reader_menu"
|
android:id="@+id/reader_menu"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:theme="?attr/actionBarTheme"
|
android:theme="?attr/actionBarTheme"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
@ -49,65 +48,9 @@
|
|||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?colorPrimary" />
|
android:background="?colorPrimary" />
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/reader_chapters_sheet"/>
|
||||||
android:id="@+id/reader_menu_bottom"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:background="?colorPrimary"
|
|
||||||
android:descendantFocusability="blocksDescendants"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<ImageButton
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
android:id="@+id/left_chapter"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/previous"
|
|
||||||
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
|
|
||||||
app:srcCompat="@drawable/ic_skip_previous_white_24dp" />
|
|
||||||
|
|
||||||
<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:maxHeight="?attr/actionBarSize"
|
|
||||||
android:minHeight="?attr/actionBarSize"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<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/next"
|
|
||||||
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
|
|
||||||
app:srcCompat="@drawable/ic_skip_next_white_24dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/brightness_overlay"
|
android:id="@+id/brightness_overlay"
|
||||||
|
64
app/src/main/res/layout/reader_chapter_item.xml
Normal file
64
app/src/main/res/layout/reader_chapter_item.xml
Normal 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"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:background="?attr/selectable_list_drawable"
|
||||||
|
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:background="@drawable/rounded_ripple"
|
||||||
|
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="?android:attr/textColorHint"/>
|
||||||
|
</FrameLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
61
app/src/main/res/layout/reader_chapters_sheet.xml
Normal file
61
app/src/main/res/layout/reader_chapters_sheet.xml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<eu.kanade.tachiyomi.ui.reader.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="@drawable/bg_bottom_sheet_black"
|
||||||
|
android:backgroundTint="@color/darkPrimaryTranslucent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:behavior_peekHeight="?attr/actionBarSize"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/title_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/chapters_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:tint="?actionBarTintColor"
|
||||||
|
android:tooltipText="@string/view_chapters"
|
||||||
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/next"
|
||||||
|
android:padding="@dimen/material_layout_keylines_screen_edge_margin"
|
||||||
|
app:srcCompat="@drawable/ic_format_list_numbered_24dp" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
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="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/page_text"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:tint="?actionBarTintColor"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="100 / 105" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/chapter_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?android:attr/colorBackground"
|
||||||
|
android:alpha="0"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
tools:listitem="@layout/reader_chapter_item"/>
|
||||||
|
</eu.kanade.tachiyomi.ui.reader.ReaderChapterSheet>
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<style name="Theme.Base.Reader" parent="Theme.Base">
|
<style name="Theme.Base.Reader" parent="Theme.Base">
|
||||||
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">false</item>
|
||||||
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
<item name="android:statusBarColor">?colorPrimaryDark</item>
|
||||||
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
<item name="android:navigationBarColor">?colorPrimaryDark</item>
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
<!--==============-->
|
<!--==============-->
|
||||||
<style name="Theme.Base.Reader" parent="Theme.Base">
|
<style name="Theme.Base.Reader" parent="Theme.Base">
|
||||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">false</item>
|
||||||
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="android:colorBackground">@android:color/white</item>
|
<item name="android:colorBackground">@android:color/white</item>
|
||||||
@ -95,6 +96,7 @@
|
|||||||
|
|
||||||
<style name="Theme.Base.Reader.Dark" parent="Theme.MaterialComponents.NoActionBar">
|
<style name="Theme.Base.Reader.Dark" parent="Theme.MaterialComponents.NoActionBar">
|
||||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">false</item>
|
||||||
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="android:colorBackground">@android:color/black</item>
|
<item name="android:colorBackground">@android:color/black</item>
|
||||||
@ -135,6 +137,7 @@
|
|||||||
|
|
||||||
<style name="Theme.Base.Reader.Light" parent="Theme.MaterialComponents.Light.NoActionBar">
|
<style name="Theme.Base.Reader.Light" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||||
|
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">false</item>
|
||||||
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimary">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
<item name="colorPrimaryDark">@color/darkPrimaryTranslucent</item>
|
||||||
<item name="android:colorBackground">@android:color/white</item>
|
<item name="android:colorBackground">@android:color/white</item>
|
||||||
@ -152,6 +155,7 @@
|
|||||||
<!-- Themes -->
|
<!-- Themes -->
|
||||||
<item name="windowActionModeOverlay">true</item>
|
<item name="windowActionModeOverlay">true</item>
|
||||||
<item name="actionBarTheme">@style/Theme.ActionBar.Dark.DayNight</item>
|
<item name="actionBarTheme">@style/Theme.ActionBar.Dark.DayNight</item>
|
||||||
|
<item name="actionBarTintColor">@color/md_white_1000</item>
|
||||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
||||||
<item name="alertDialogTheme">@style/Theme.AlertDialog.DayNight</item>
|
<item name="alertDialogTheme">@style/Theme.AlertDialog.DayNight</item>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user