优化
This commit is contained in:
@@ -136,6 +136,8 @@ object ReadBook : CoroutineScope by MainScope() {
|
|||||||
TextFile.clear()
|
TextFile.clear()
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
loadingChapters.clear()
|
loadingChapters.clear()
|
||||||
|
downloadedChapters.clear()
|
||||||
|
downloadFailChapters.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,8 +956,6 @@ object ReadBook : CoroutineScope by MainScope() {
|
|||||||
preDownloadTask?.cancel()
|
preDownloadTask?.cancel()
|
||||||
downloadScope.coroutineContext.cancelChildren()
|
downloadScope.coroutineContext.cancelChildren()
|
||||||
coroutineContext.cancelChildren()
|
coroutineContext.cancelChildren()
|
||||||
downloadedChapters.clear()
|
|
||||||
downloadFailChapters.clear()
|
|
||||||
ImageProvider.clear()
|
ImageProvider.clear()
|
||||||
if (!CacheBookService.isRun) {
|
if (!CacheBookService.isRun) {
|
||||||
CacheBook.close()
|
CacheBook.close()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.legado.app.help.config.AppConfig
|
|||||||
import io.legado.app.help.coroutine.Coroutine
|
import io.legado.app.help.coroutine.Coroutine
|
||||||
import io.legado.app.help.globalExecutor
|
import io.legado.app.help.globalExecutor
|
||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
|
import io.legado.app.ui.book.manga.entities.MangaChapter
|
||||||
import io.legado.app.ui.book.manga.entities.MangaContent
|
import io.legado.app.ui.book.manga.entities.MangaContent
|
||||||
import io.legado.app.ui.book.manga.entities.ReaderLoading
|
import io.legado.app.ui.book.manga.entities.ReaderLoading
|
||||||
import io.legado.app.utils.NetworkUtils
|
import io.legado.app.utils.NetworkUtils
|
||||||
@@ -50,19 +51,23 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
var chapterSize = 0//总章节
|
var chapterSize = 0//总章节
|
||||||
var durChapterImageCount = 0
|
var durChapterImageCount = 0
|
||||||
var durChapterPos = 0
|
var durChapterPos = 0
|
||||||
|
var prevMangaChapter: MangaChapter? = null
|
||||||
|
var curMangaChapter: MangaChapter? = null
|
||||||
|
var nextMangaChapter: MangaChapter? = null
|
||||||
var bookSource: BookSource? = null
|
var bookSource: BookSource? = null
|
||||||
var chapterTitle: String = ""
|
|
||||||
var readStartTime: Long = System.currentTimeMillis()
|
var readStartTime: Long = System.currentTimeMillis()
|
||||||
private val readRecord = ReadRecord()
|
private val readRecord = ReadRecord()
|
||||||
private val loadingChapters = arrayListOf<Int>()
|
private val loadingChapters = arrayListOf<Int>()
|
||||||
var simulatedChapterSize = 0
|
var simulatedChapterSize = 0
|
||||||
var mCallback: Callback? = null
|
var mCallback: Callback? = null
|
||||||
var gameOver = false
|
|
||||||
var preDownloadTask: Job? = null
|
var preDownloadTask: Job? = null
|
||||||
val downloadedChapters = hashSetOf<Int>()
|
val downloadedChapters = hashSetOf<Int>()
|
||||||
val downloadFailChapters = hashMapOf<Int, Int>()
|
val downloadFailChapters = hashMapOf<Int, Int>()
|
||||||
val downloadScope = CoroutineScope(SupervisorJob() + IO)
|
val downloadScope = CoroutineScope(SupervisorJob() + IO)
|
||||||
var rateLimiter = ConcurrentRateLimiter(null)
|
var rateLimiter = ConcurrentRateLimiter(null)
|
||||||
|
val durChapterAbsPos get() = (prevMangaChapter?.contents?.size ?: 0) + durChapterPos + 1
|
||||||
|
val mangaContents get() = buildContentList()
|
||||||
|
val hasNextChapter get() = durChapterIndex < simulatedChapterSize - 1
|
||||||
|
|
||||||
fun saveRead(pageChanged: Boolean = false) {
|
fun saveRead(pageChanged: Boolean = false) {
|
||||||
executor.execute {
|
executor.execute {
|
||||||
@@ -115,9 +120,12 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
}
|
}
|
||||||
durChapterIndex = book.durChapterIndex
|
durChapterIndex = book.durChapterIndex
|
||||||
durChapterPos = book.durChapterPos
|
durChapterPos = book.durChapterPos
|
||||||
|
clearMangaChapter()
|
||||||
upWebBook(book)
|
upWebBook(book)
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
loadingChapters.clear()
|
loadingChapters.clear()
|
||||||
|
downloadedChapters.clear()
|
||||||
|
downloadFailChapters.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +138,11 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearMangaChapter() {
|
||||||
|
prevMangaChapter = null
|
||||||
|
curMangaChapter = null
|
||||||
|
nextMangaChapter = null
|
||||||
|
}
|
||||||
|
|
||||||
//每次切换章节更新阅读记录
|
//每次切换章节更新阅读记录
|
||||||
fun upReadTime() {
|
fun upReadTime() {
|
||||||
@@ -158,12 +171,6 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loading(index: Int): Boolean {
|
|
||||||
synchronized(this) {
|
|
||||||
return loadingChapters.contains(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取正文
|
* 获取正文
|
||||||
*/
|
*/
|
||||||
@@ -188,11 +195,25 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
|
|
||||||
fun loadContent() {
|
fun loadContent() {
|
||||||
loadContent(durChapterIndex)
|
loadContent(durChapterIndex)
|
||||||
|
loadContent(durChapterIndex - 1)
|
||||||
|
loadContent(durChapterIndex + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadContent(
|
fun loadOrUpContent() {
|
||||||
index: Int,
|
if (curMangaChapter == null) {
|
||||||
) {
|
loadContent(durChapterIndex)
|
||||||
|
} else {
|
||||||
|
mCallback?.upContent(true)
|
||||||
|
}
|
||||||
|
if (nextMangaChapter == null) {
|
||||||
|
loadContent(durChapterIndex + 1)
|
||||||
|
}
|
||||||
|
if (prevMangaChapter == null) {
|
||||||
|
loadContent(durChapterIndex - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadContent(index: Int) {
|
||||||
if (chapterChanged) {
|
if (chapterChanged) {
|
||||||
removeLoading(index)
|
removeLoading(index)
|
||||||
}
|
}
|
||||||
@@ -225,25 +246,20 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
/**
|
/**
|
||||||
* 取消注册回调
|
* 取消注册回调
|
||||||
*/
|
*/
|
||||||
fun unregister() {
|
fun unregister(cb: Callback) {
|
||||||
|
if (mCallback === cb) {
|
||||||
|
mCallback = null
|
||||||
|
}
|
||||||
inBookshelf = false
|
inBookshelf = false
|
||||||
tocChanged = false
|
tocChanged = false
|
||||||
chapterChanged = false
|
chapterChanged = false
|
||||||
book = null
|
|
||||||
durChapterIndex = 0
|
durChapterIndex = 0
|
||||||
chapterSize = 0
|
chapterSize = 0
|
||||||
durChapterPos = 0
|
durChapterPos = 0
|
||||||
durChapterImageCount = 0
|
durChapterImageCount = 0
|
||||||
bookSource = null
|
|
||||||
chapterTitle = ""
|
|
||||||
loadingChapters.clear()
|
|
||||||
simulatedChapterSize = 0
|
simulatedChapterSize = 0
|
||||||
mCallback = null
|
|
||||||
gameOver = false
|
|
||||||
preDownloadTask?.cancel()
|
preDownloadTask?.cancel()
|
||||||
preDownloadTask = null
|
preDownloadTask = null
|
||||||
downloadedChapters.clear()
|
|
||||||
downloadFailChapters.clear()
|
|
||||||
downloadScope.coroutineContext.cancelChildren()
|
downloadScope.coroutineContext.cancelChildren()
|
||||||
coroutineContext.cancelChildren()
|
coroutineContext.cancelChildren()
|
||||||
}
|
}
|
||||||
@@ -256,122 +272,119 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
content: String?,
|
content: String?,
|
||||||
book: Book,
|
book: Book,
|
||||||
) {
|
) {
|
||||||
chapterTitle = chapter.title
|
|
||||||
removeLoading(chapter.index)
|
removeLoading(chapter.index)
|
||||||
if (chapter.index !in durChapterIndex - 1..durChapterIndex + 1) {
|
if (chapter.index !in durChapterIndex - 1..durChapterIndex + 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (content == null) {
|
when (chapter.index - durChapterIndex) {
|
||||||
mCallback?.loadFail("加载内容失败")
|
0 -> {
|
||||||
return
|
if (content == null) {
|
||||||
}
|
mCallback?.loadFail("加载内容失败")
|
||||||
if (content.isNotEmpty()) {
|
return
|
||||||
val list = flow {
|
|
||||||
val matcher = AppPattern.imgPattern.matcher(content)
|
|
||||||
while (matcher.find()) {
|
|
||||||
val src = matcher.group(1) ?: continue
|
|
||||||
val mSrc = NetworkUtils.getAbsoluteURL(chapter.url, src)
|
|
||||||
emit(mSrc)
|
|
||||||
}
|
}
|
||||||
}.distinctUntilChanged().mapIndexed { index, src ->
|
if (content.isEmpty()) {
|
||||||
MangaContent(
|
mCallback?.loadFail("正文内容为空")
|
||||||
chapterSize = chapterSize,
|
return
|
||||||
mChapterIndex = durChapterIndex,
|
|
||||||
nextChapterIndex = durChapterIndex.plus(1),
|
|
||||||
mImageUrl = src,
|
|
||||||
mDurChapterPos = index,
|
|
||||||
mChapterName = chapterTitle
|
|
||||||
)
|
|
||||||
}.toList().apply {
|
|
||||||
this.forEach {
|
|
||||||
it.mDurChapterCount = this.size
|
|
||||||
}
|
}
|
||||||
durChapterImageCount = this.size
|
val mangaChapter = getManageChapter(chapter, content)
|
||||||
|
if (mangaChapter.imageCount == 0) {
|
||||||
|
mCallback?.loadFail("正文没有图片")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
durChapterImageCount = mangaChapter.imageCount
|
||||||
|
curMangaChapter = mangaChapter
|
||||||
|
mCallback?.upContent(true)
|
||||||
|
mCallback?.contentLoadFinish()
|
||||||
|
}
|
||||||
|
|
||||||
|
-1 -> {
|
||||||
|
if (content == null || content.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val mangaChapter = getManageChapter(chapter, content)
|
||||||
|
if (mangaChapter.imageCount == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
prevMangaChapter = mangaChapter
|
||||||
|
mCallback?.upContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
1 -> {
|
||||||
|
if (content == null || content.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val mangaChapter = getManageChapter(chapter, content)
|
||||||
|
if (mangaChapter.imageCount == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nextMangaChapter = mangaChapter
|
||||||
|
mCallback?.upContent()
|
||||||
}
|
}
|
||||||
val contentList = mutableListOf<Any>()
|
|
||||||
contentList.add(
|
|
||||||
ReaderLoading(
|
|
||||||
durChapterIndex,
|
|
||||||
"阅读 ${chapter.title}",
|
|
||||||
mNextChapterIndex = durChapterIndex.plus(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
contentList.addAll(list)
|
|
||||||
contentList.add(
|
|
||||||
ReaderLoading(
|
|
||||||
durChapterIndex,
|
|
||||||
"已读完 ${chapter.title}",
|
|
||||||
mNextChapterIndex = durChapterIndex.plus(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
mCallback?.loadContentFinish(contentList)
|
|
||||||
}
|
}
|
||||||
mCallback?.loadComplete()
|
}
|
||||||
|
|
||||||
|
private fun buildContentList(): List<Any> {
|
||||||
|
val list = arrayListOf<Any>()
|
||||||
|
prevMangaChapter?.let {
|
||||||
|
list.addAll(it.contents)
|
||||||
|
}
|
||||||
|
curMangaChapter?.let {
|
||||||
|
list.addAll(it.contents)
|
||||||
|
}
|
||||||
|
nextMangaChapter?.let {
|
||||||
|
list.addAll(it.contents)
|
||||||
|
}
|
||||||
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载下一章
|
* 加载下一章
|
||||||
*/
|
*/
|
||||||
fun moveToNextChapter(index: Int) {
|
fun moveToNextChapter(): Boolean {
|
||||||
|
|
||||||
if (loading(index)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > chapterSize - 1) {
|
|
||||||
upToc(index)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (durChapterIndex < simulatedChapterSize - 1) {
|
if (durChapterIndex < simulatedChapterSize - 1) {
|
||||||
durChapterPos = 0
|
durChapterIndex++
|
||||||
durChapterIndex = index
|
prevMangaChapter = curMangaChapter
|
||||||
|
curMangaChapter = nextMangaChapter
|
||||||
|
nextMangaChapter = null
|
||||||
|
if (curMangaChapter == null) {
|
||||||
|
loadContent(durChapterIndex)
|
||||||
|
} else {
|
||||||
|
mCallback?.upContent(true)
|
||||||
|
}
|
||||||
|
loadContent(durChapterIndex + 1)
|
||||||
saveRead()
|
saveRead()
|
||||||
loadContent(durChapterIndex)
|
|
||||||
AppLog.putDebug("moveToNextChapter-curPageChanged()")
|
AppLog.putDebug("moveToNextChapter-curPageChanged()")
|
||||||
curPageChanged()
|
curPageChanged()
|
||||||
|
return true
|
||||||
} else {
|
} else {
|
||||||
AppLog.putDebug("跳转下一章失败,没有下一章")
|
AppLog.putDebug("跳转下一章失败,没有下一章")
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun moveToPrevChapter(): Boolean {
|
||||||
|
if (durChapterIndex > 0) {
|
||||||
|
durChapterIndex--
|
||||||
|
nextMangaChapter = curMangaChapter
|
||||||
|
curMangaChapter = prevMangaChapter
|
||||||
|
prevMangaChapter = null
|
||||||
|
if (curMangaChapter == null) {
|
||||||
|
loadContent(durChapterIndex)
|
||||||
|
} else {
|
||||||
|
mCallback?.upContent(true)
|
||||||
|
}
|
||||||
|
loadContent(durChapterIndex - 1)
|
||||||
|
saveRead()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun curPageChanged() {
|
fun curPageChanged() {
|
||||||
upReadTime()
|
upReadTime()
|
||||||
preDownload()
|
preDownload()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun upToc(index: Int) {
|
|
||||||
val bookSource = bookSource ?: return
|
|
||||||
val book = book ?: return
|
|
||||||
if (!book.canUpdate) return
|
|
||||||
if (System.currentTimeMillis() - book.lastCheckTime < 600000) {
|
|
||||||
mCallback?.noData()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
book.lastCheckTime = System.currentTimeMillis()
|
|
||||||
WebBook.getChapterList(this, bookSource, book).onSuccess(IO) { cList ->
|
|
||||||
if (book.bookUrl == ReadManga.book?.bookUrl
|
|
||||||
&& cList.size > chapterSize
|
|
||||||
) {
|
|
||||||
appDb.bookChapterDao.delByBook(book.bookUrl)
|
|
||||||
appDb.bookChapterDao.insert(*cList.toTypedArray())
|
|
||||||
saveRead()
|
|
||||||
durChapterPos = 0
|
|
||||||
durChapterIndex = index
|
|
||||||
chapterSize = cList.size
|
|
||||||
simulatedChapterSize = book.simulatedTotalChapterNum()
|
|
||||||
loadContent(durChapterIndex)
|
|
||||||
} else {
|
|
||||||
durChapterIndex = durChapterIndex.minus(1)
|
|
||||||
saveRead()
|
|
||||||
gameOver = true
|
|
||||||
mCallback?.noData()
|
|
||||||
}
|
|
||||||
}.onError {
|
|
||||||
mCallback?.noData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun downloadNetworkContent(
|
private fun downloadNetworkContent(
|
||||||
bookSource: BookSource,
|
bookSource: BookSource,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
@@ -480,7 +493,6 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步阅读进度
|
* 同步阅读进度
|
||||||
* 如果当前进度快于服务器进度或者没有进度进行上传,如果慢与服务器进度则执行传入动作
|
* 如果当前进度快于服务器进度或者没有进度进行上传,如果慢与服务器进度则执行传入动作
|
||||||
@@ -536,11 +548,55 @@ object ReadManga : CoroutineScope by MainScope() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getManageChapter(chapter: BookChapter, content: String): MangaChapter {
|
||||||
|
val list = flow {
|
||||||
|
val matcher = AppPattern.imgPattern.matcher(content)
|
||||||
|
while (matcher.find()) {
|
||||||
|
val src = matcher.group(1) ?: continue
|
||||||
|
val mSrc = NetworkUtils.getAbsoluteURL(chapter.url, src)
|
||||||
|
emit(mSrc)
|
||||||
|
}
|
||||||
|
}.distinctUntilChanged().mapIndexed { index, src ->
|
||||||
|
MangaContent(
|
||||||
|
chapterSize = chapterSize,
|
||||||
|
mChapterIndex = chapter.index,
|
||||||
|
nextChapterIndex = chapter.index.plus(1),
|
||||||
|
mImageUrl = src,
|
||||||
|
mDurChapterPos = index,
|
||||||
|
mChapterName = chapter.title
|
||||||
|
)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
val imageCount = list.size
|
||||||
|
|
||||||
|
list.forEach {
|
||||||
|
it.mDurChapterImageCount = imageCount
|
||||||
|
}
|
||||||
|
|
||||||
|
val contentList = mutableListOf<Any>()
|
||||||
|
contentList.add(
|
||||||
|
ReaderLoading(
|
||||||
|
chapter.index,
|
||||||
|
"阅读 ${chapter.title}",
|
||||||
|
mNextChapterIndex = chapter.index.plus(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
contentList.addAll(list)
|
||||||
|
contentList.add(
|
||||||
|
ReaderLoading(
|
||||||
|
chapter.index,
|
||||||
|
"已读完 ${chapter.title}",
|
||||||
|
mNextChapterIndex = chapter.index.plus(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return MangaChapter(chapter, contentList, imageCount)
|
||||||
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun loadContentFinish(list: MutableList<Any>)
|
fun upContent(finish: Boolean = false)
|
||||||
fun loadComplete()
|
fun contentLoadFinish()
|
||||||
fun loadFail(msg: String)
|
fun loadFail(msg: String)
|
||||||
fun noData()
|
|
||||||
fun adjustProgress()
|
fun adjustProgress()
|
||||||
fun sureNewProgress(progress: BookProgress)
|
fun sureNewProgress(progress: BookProgress)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,13 +39,12 @@ import io.legado.app.help.config.AppConfig
|
|||||||
import io.legado.app.help.storage.Backup
|
import io.legado.app.help.storage.Backup
|
||||||
import io.legado.app.lib.dialogs.alert
|
import io.legado.app.lib.dialogs.alert
|
||||||
import io.legado.app.model.ReadManga
|
import io.legado.app.model.ReadManga
|
||||||
import io.legado.app.ui.book.manga.entities.MangaContent
|
|
||||||
import io.legado.app.ui.book.manga.entities.ReaderLoading
|
|
||||||
import io.legado.app.receiver.NetworkChangedListener
|
import io.legado.app.receiver.NetworkChangedListener
|
||||||
import io.legado.app.ui.book.changesource.ChangeBookSourceDialog
|
import io.legado.app.ui.book.changesource.ChangeBookSourceDialog
|
||||||
import io.legado.app.ui.book.info.BookInfoActivity
|
import io.legado.app.ui.book.info.BookInfoActivity
|
||||||
import io.legado.app.ui.book.manga.config.MangaFooterConfig
|
import io.legado.app.ui.book.manga.config.MangaFooterConfig
|
||||||
import io.legado.app.ui.book.manga.config.MangaFooterSettingDialog
|
import io.legado.app.ui.book.manga.config.MangaFooterSettingDialog
|
||||||
|
import io.legado.app.ui.book.manga.entities.MangaContent
|
||||||
import io.legado.app.ui.book.manga.recyclerview.MangaAdapter
|
import io.legado.app.ui.book.manga.recyclerview.MangaAdapter
|
||||||
import io.legado.app.ui.book.read.MangaMenu
|
import io.legado.app.ui.book.read.MangaMenu
|
||||||
import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED
|
import io.legado.app.ui.book.read.ReadBookActivity.Companion.RESULT_DELETED
|
||||||
@@ -64,9 +63,12 @@ import io.legado.app.utils.toastOnUi
|
|||||||
import io.legado.app.utils.toggleStatusBar
|
import io.legado.app.utils.toggleStatusBar
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import io.legado.app.utils.visible
|
import io.legado.app.utils.visible
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>(),
|
class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewModel>(),
|
||||||
ReadManga.Callback, ChangeBookSourceDialog.CallBack, MangaMenu.CallBack {
|
ReadManga.Callback, ChangeBookSourceDialog.CallBack, MangaMenu.CallBack {
|
||||||
|
|
||||||
private val mLayoutManager by lazy {
|
private val mLayoutManager by lazy {
|
||||||
@@ -140,7 +142,11 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
override val binding by viewBinding(ActivityMangaBinding::inflate)
|
override val binding by viewBinding(ActivityMangaBinding::inflate)
|
||||||
override val viewModel by viewModels<MangaViewModel>()
|
override val viewModel by viewModels<ReadMangaViewModel>()
|
||||||
|
private val loadingViewVisible get() = binding.flLoading.isVisible
|
||||||
|
private val df by lazy {
|
||||||
|
DecimalFormat("0.0%")
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
upLayoutInDisplayCutoutMode()
|
upLayoutInDisplayCutoutMode()
|
||||||
@@ -154,15 +160,15 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
binding.tvRetry.setOnClickListener {
|
binding.tvRetry.setOnClickListener {
|
||||||
binding.llLoading.isVisible = true
|
binding.llLoading.isVisible = true
|
||||||
binding.llRetry.isGone = true
|
binding.llRetry.isGone = true
|
||||||
ReadManga.loadContent()
|
ReadManga.loadOrUpContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
mAdapter.addFooterView {
|
mAdapter.addFooterView {
|
||||||
ViewLoadMoreBinding.bind(loadMoreView)
|
ViewLoadMoreBinding.bind(loadMoreView)
|
||||||
}
|
}
|
||||||
loadMoreView.setOnClickListener {
|
loadMoreView.setOnClickListener {
|
||||||
if (!loadMoreView.isLoading && !ReadManga.gameOver) {
|
if (!loadMoreView.isLoading && ReadManga.hasNextChapter) {
|
||||||
scrollToBottom(true, ReadManga.durChapterIndex)
|
loadMoreView.startLoad()
|
||||||
|
ReadManga.loadOrUpContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadMoreView.gone()
|
loadMoreView.gone()
|
||||||
@@ -175,11 +181,11 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
observeEvent<MangaFooterConfig>(EventBus.UP_MANGA_CONFIG) {
|
observeEvent<MangaFooterConfig>(EventBus.UP_MANGA_CONFIG) {
|
||||||
mMangaFooterConfig = it
|
mMangaFooterConfig = it
|
||||||
upInfoBar(
|
upInfoBar(
|
||||||
ReadManga.durChapterIndex.plus(1),
|
ReadManga.durChapterIndex,
|
||||||
ReadManga.chapterSize,
|
ReadManga.chapterSize,
|
||||||
ReadManga.durChapterPos.plus(1),
|
ReadManga.durChapterPos,
|
||||||
ReadManga.durChapterImageCount,
|
ReadManga.durChapterImageCount,
|
||||||
ReadManga.chapterTitle
|
ReadManga.curMangaChapter?.chapter?.title ?: ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,28 +203,28 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
singlePagerScroller(AppConfig.enableMangaHorizontalScroll)
|
singlePagerScroller(AppConfig.enableMangaHorizontalScroll)
|
||||||
disabledClickScroller(AppConfig.disableClickScroll)
|
disabledClickScroller(AppConfig.disableClickScroll)
|
||||||
disableMangaScaling(AppConfig.disableMangaScale)
|
disableMangaScaling(AppConfig.disableMangaScale)
|
||||||
setPreScrollListener { _, dx, dy, position ->
|
setPreScrollListener { _, _, _, position ->
|
||||||
if ((dy > 0 || dx > 0) && position + 2 > mAdapter.getCurrentList().size - 3) {
|
|
||||||
if (mAdapter.getCurrentList().last() is ReaderLoading) {
|
|
||||||
val nextIndex =
|
|
||||||
(mAdapter.getCurrentList().last() as ReaderLoading).mNextChapterIndex
|
|
||||||
if (nextIndex != -1) {
|
|
||||||
scrollToBottom(false, nextIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setNestedPreScrollListener { _, _, _, position ->
|
|
||||||
if (mAdapter.isNotEmpty()) {
|
if (mAdapter.isNotEmpty()) {
|
||||||
val content = mAdapter.getItem(position)
|
val content = mAdapter.getItem(position)
|
||||||
if (content is MangaContent) {
|
if (content is MangaContent) {
|
||||||
ReadManga.durChapterIndex = content.mChapterIndex
|
if (ReadManga.durChapterIndex < content.mChapterIndex) {
|
||||||
ReadManga.durChapterPos = content.mDurChapterPos
|
ReadManga.moveToNextChapter()
|
||||||
|
if (ReadManga.hasNextChapter) {
|
||||||
|
loadMoreView.startLoad()
|
||||||
|
} else {
|
||||||
|
loadMoreView.noMore("暂无章节了!")
|
||||||
|
}
|
||||||
|
} else if (ReadManga.durChapterIndex > content.mChapterIndex) {
|
||||||
|
ReadManga.moveToPrevChapter()
|
||||||
|
} else {
|
||||||
|
ReadManga.durChapterPos = content.mDurChapterPos
|
||||||
|
ReadManga.curPageChanged()
|
||||||
|
}
|
||||||
upInfoBar(
|
upInfoBar(
|
||||||
content.mChapterIndex + 1,
|
content.mChapterIndex,
|
||||||
content.chapterSize,
|
content.chapterSize,
|
||||||
content.mDurChapterPos + 1,
|
content.mDurChapterPos,
|
||||||
content.mDurChapterCount,
|
content.mDurChapterImageCount,
|
||||||
content.mChapterName
|
content.mChapterName
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -244,13 +250,6 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
viewModel.initData(intent)
|
viewModel.initData(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToBottom(forceLoad: Boolean = false, index: Int) {
|
|
||||||
if ((loadMoreView.hasMore && !loadMoreView.isLoading) && !ReadManga.gameOver || forceLoad) {
|
|
||||||
loadMoreView.hasMore()
|
|
||||||
ReadManga.moveToNextChapter(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPostCreate(savedInstanceState: Bundle?) {
|
override fun onPostCreate(savedInstanceState: Bundle?) {
|
||||||
super.onPostCreate(savedInstanceState)
|
super.onPostCreate(savedInstanceState)
|
||||||
Looper.myQueue().addIdleHandler {
|
Looper.myQueue().addIdleHandler {
|
||||||
@@ -260,41 +259,47 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
justInitData = true
|
justInitData = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadContentFinish(list: MutableList<Any>) {
|
override fun upContent(finish: Boolean) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
setTitle(ReadManga.book?.name)
|
setTitle(ReadManga.book?.name)
|
||||||
val isEmpty = mAdapter.isEmpty()
|
val list = withContext(IO) { ReadManga.mangaContents }
|
||||||
mAdapter.submitList(list) {
|
mAdapter.submitList(list) {
|
||||||
if (isEmpty) {
|
if (loadingViewVisible && finish) {
|
||||||
binding.infobar.isVisible = true
|
binding.infobar.isVisible = true
|
||||||
upInfoBar(
|
upInfoBar(
|
||||||
ReadManga.durChapterIndex.plus(1),
|
ReadManga.durChapterIndex,
|
||||||
ReadManga.chapterSize,
|
ReadManga.chapterSize,
|
||||||
ReadManga.durChapterPos.plus(1),
|
ReadManga.durChapterPos,
|
||||||
ReadManga.durChapterImageCount,
|
ReadManga.durChapterImageCount,
|
||||||
ReadManga.chapterTitle
|
ReadManga.curMangaChapter!!.chapter.title
|
||||||
)
|
)
|
||||||
|
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterAbsPos)
|
||||||
|
binding.flLoading.isGone = true
|
||||||
|
loadMoreView.visible()
|
||||||
|
}
|
||||||
|
|
||||||
if (ReadManga.durChapterPos + 2 > mAdapter.getCurrentList().size - 3) {
|
if (finish) {
|
||||||
val nextIndex =
|
loadMoreView.stopLoad()
|
||||||
(mAdapter.getCurrentList().last() as ReaderLoading).mNextChapterIndex
|
if (!ReadManga.hasNextChapter) {
|
||||||
scrollToBottom(index = nextIndex)
|
loadMoreView.noMore("暂无章节了!")
|
||||||
} else {
|
|
||||||
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterPos)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReadManga.chapterChanged) {
|
if (ReadManga.chapterChanged) {
|
||||||
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterPos)
|
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterAbsPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadManga.chapterChanged = false
|
ReadManga.chapterChanged = false
|
||||||
loadMoreView.visible()
|
|
||||||
loadMoreView.stopLoad()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun contentLoadFinish() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
loadMoreView.stopLoad()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun upInfoBar(
|
private fun upInfoBar(
|
||||||
chapterIndex: Int,
|
chapterIndex: Int,
|
||||||
chapterSize: Int,
|
chapterSize: Int,
|
||||||
@@ -315,21 +320,35 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
if (!hidePageNumberLabel) {
|
if (!hidePageNumberLabel) {
|
||||||
mLabelBuilder.append(getString(R.string.manga_check_page_number))
|
mLabelBuilder.append(getString(R.string.manga_check_page_number))
|
||||||
}
|
}
|
||||||
mLabelBuilder.append("${chapterPos}/${chapterImageCount}").append(" ")
|
mLabelBuilder.append("${chapterPos + 1}/${chapterImageCount}").append(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hideChapter) {
|
if (!hideChapter) {
|
||||||
if (!hideChapterLabel) {
|
if (!hideChapterLabel) {
|
||||||
mLabelBuilder.append(getString(R.string.manga_check_chapter))
|
mLabelBuilder.append(getString(R.string.manga_check_chapter))
|
||||||
}
|
}
|
||||||
mLabelBuilder.append("${chapterIndex}/${chapterSize}").append(" ")
|
mLabelBuilder.append("${chapterIndex + 1}/${chapterSize}").append(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hideProgressRatio) {
|
if (!hideProgressRatio) {
|
||||||
if (!hideProgressRatioLabel) {
|
if (!hideProgressRatioLabel) {
|
||||||
mLabelBuilder.append(getString(R.string.manga_check_progress))
|
mLabelBuilder.append(getString(R.string.manga_check_progress))
|
||||||
}
|
}
|
||||||
mLabelBuilder.append("${chapterIndex.div(chapterSize).times(100)}%")
|
val percent = if (chapterSize == 0 || chapterImageCount == 0 && chapterIndex == 0) {
|
||||||
|
"0.0%"
|
||||||
|
} else if (chapterImageCount == 0) {
|
||||||
|
df.format((chapterIndex + 1.0f) / chapterSize.toDouble())
|
||||||
|
} else {
|
||||||
|
var percent =
|
||||||
|
df.format(
|
||||||
|
chapterIndex * 1.0f / chapterSize + 1.0f / chapterSize * (chapterPos + 1) / chapterImageCount.toDouble()
|
||||||
|
)
|
||||||
|
if (percent == "100.0%" && (chapterIndex + 1 != chapterSize || chapterPos + 1 != chapterImageCount)) {
|
||||||
|
percent = "99.9%"
|
||||||
|
}
|
||||||
|
percent
|
||||||
|
}
|
||||||
|
mLabelBuilder.append(percent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.infobar.update(
|
binding.infobar.update(
|
||||||
@@ -366,15 +385,9 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
stopAutoPage()
|
stopAutoPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadComplete() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
binding.flLoading.isGone = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadFail(msg: String) {
|
override fun loadFail(msg: String) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
if (mAdapter.isEmpty() || ReadManga.chapterChanged) {
|
if (loadingViewVisible) {
|
||||||
binding.llLoading.isGone = true
|
binding.llLoading.isGone = true
|
||||||
binding.llRetry.isVisible = true
|
binding.llRetry.isVisible = true
|
||||||
binding.tvMsg.text = msg
|
binding.tvMsg.text = msg
|
||||||
@@ -384,12 +397,6 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun noData() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
loadMoreView.noMore("暂无章节了!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun adjustProgress() {
|
override fun adjustProgress() {
|
||||||
if (ReadManga.chapterChanged) {
|
if (ReadManga.chapterChanged) {
|
||||||
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterPos)
|
binding.mRecyclerManga.scrollToPosition(ReadManga.durChapterPos)
|
||||||
@@ -398,7 +405,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, MangaViewModel>()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
ReadManga.unregister()
|
ReadManga.unregister(this)
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -33,7 +33,7 @@ import kotlinx.coroutines.flow.onEmpty
|
|||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.take
|
import kotlinx.coroutines.flow.take
|
||||||
|
|
||||||
class MangaViewModel(application: Application) : BaseViewModel(application) {
|
class ReadMangaViewModel(application: Application) : BaseViewModel(application) {
|
||||||
|
|
||||||
private var changeSourceCoroutine: Coroutine<*>? = null
|
private var changeSourceCoroutine: Coroutine<*>? = null
|
||||||
|
|
||||||
@@ -84,7 +84,12 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
ensureChapterExist()
|
ensureChapterExist()
|
||||||
|
|
||||||
//开始加载内容
|
//开始加载内容
|
||||||
ReadManga.loadContent()
|
if (!isSameBook) {
|
||||||
|
ReadManga.loadContent()
|
||||||
|
} else {
|
||||||
|
ReadManga.loadOrUpContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//自动换源
|
//自动换源
|
||||||
if (!book.isLocal && ReadManga.bookSource == null) {
|
if (!book.isLocal && ReadManga.bookSource == null) {
|
||||||
@@ -224,7 +229,7 @@ class MangaViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
ReadManga.durChapterIndex = index
|
ReadManga.durChapterIndex = index
|
||||||
ReadManga.durChapterPos = durChapterPos
|
ReadManga.durChapterPos = durChapterPos
|
||||||
ReadManga.saveRead()
|
ReadManga.saveRead()
|
||||||
ReadManga.loadContent(index)
|
ReadManga.loadContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package io.legado.app.ui.book.manga.entities
|
||||||
|
|
||||||
|
import io.legado.app.data.entities.BookChapter
|
||||||
|
|
||||||
|
data class MangaChapter(
|
||||||
|
val chapter: BookChapter,
|
||||||
|
val contents: List<Any>,
|
||||||
|
val imageCount: Int
|
||||||
|
)
|
||||||
@@ -6,6 +6,6 @@ data class MangaContent(
|
|||||||
var nextChapterIndex: Int = 0,//下一章
|
var nextChapterIndex: Int = 0,//下一章
|
||||||
val mImageUrl: String = "",//当前URL
|
val mImageUrl: String = "",//当前URL
|
||||||
var mDurChapterPos: Int = 0,//当前章节位置
|
var mDurChapterPos: Int = 0,//当前章节位置
|
||||||
var mDurChapterCount: Int = 0,//当前章节内容总数
|
var mDurChapterImageCount: Int = 0,//当前章节内容总数
|
||||||
var mChapterName: String = "",//章节名称
|
var mChapterName: String = "",//章节名称
|
||||||
)
|
)
|
||||||
@@ -67,17 +67,8 @@ class MangaAdapter(private val context: Context) :
|
|||||||
fun isNotEmpty() = !isEmpty()
|
fun isNotEmpty() = !isEmpty()
|
||||||
|
|
||||||
//全部替换数据
|
//全部替换数据
|
||||||
fun submitList(contents: MutableList<Any>, runnable: Runnable) {
|
fun submitList(contents: List<Any>, runnable: Runnable? = null) {
|
||||||
val list = if (ReadManga.chapterChanged) {
|
mDiffer.submitList(contents, runnable)
|
||||||
contents
|
|
||||||
} else {
|
|
||||||
val currentList = mDiffer.currentList.toMutableList()
|
|
||||||
currentList.addAll(contents)
|
|
||||||
currentList
|
|
||||||
}
|
|
||||||
mDiffer.submitList(list) {
|
|
||||||
runnable.run()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class PageViewHolder(binding: BookComicRvBinding) :
|
inner class PageViewHolder(binding: BookComicRvBinding) :
|
||||||
@@ -94,13 +85,13 @@ class MangaAdapter(private val context: Context) :
|
|||||||
binding.retry.setOnClickListener {
|
binding.retry.setOnClickListener {
|
||||||
val item = mDiffer.currentList[layoutPosition]
|
val item = mDiffer.currentList[layoutPosition]
|
||||||
if (item is MangaContent) {
|
if (item is MangaContent) {
|
||||||
loadImageWithRetry(item.mImageUrl, isHorizontal)
|
loadImageWithRetry(item.mImageUrl, isHorizontal, mDiffer.currentList.size == 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onBind(item: MangaContent) {
|
fun onBind(item: MangaContent) {
|
||||||
loadImageWithRetry(item.mImageUrl, isHorizontal)
|
loadImageWithRetry(item.mImageUrl, isHorizontal, mDiffer.currentList.size == 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ open class MangaVH<VB : ViewBinding>(val binding: VB, private val context: Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
fun loadImageWithRetry(imageUrl: String, isHorizontal: Boolean) {
|
fun loadImageWithRetry(imageUrl: String, isHorizontal: Boolean, singleImage: Boolean) {
|
||||||
mFlProgress.isVisible = true
|
mFlProgress.isVisible = true
|
||||||
mLoading.isVisible = true
|
mLoading.isVisible = true
|
||||||
mRetry?.isGone = true
|
mRetry?.isGone = true
|
||||||
@@ -95,7 +95,11 @@ open class MangaVH<VB : ViewBinding>(val binding: VB, private val context: Conte
|
|||||||
mFlProgress.isGone = true
|
mFlProgress.isGone = true
|
||||||
if (!isHorizontal) {
|
if (!isHorizontal) {
|
||||||
itemView.updateLayoutParams<ViewGroup.LayoutParams> {
|
itemView.updateLayoutParams<ViewGroup.LayoutParams> {
|
||||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
height = if (singleImage) {
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
} else {
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mImage.updateLayoutParams<FrameLayout.LayoutParams> {
|
mImage.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
fun RecyclerView.findCenterViewPosition(): Int {
|
fun RecyclerView.findCenterViewPosition(): Int {
|
||||||
return getChildAdapterPosition(findChildViewUnder(width / 2f, height / 2f) ?: return RecyclerView.NO_POSITION)
|
return getChildAdapterPosition(
|
||||||
|
findChildViewUnder(width / 2f, height / 2f) ?: return RecyclerView.NO_POSITION
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RecyclerView.findViewPosition(x: Float, y: Float): Int {
|
fun RecyclerView.findViewPosition(x: Float, y: Float): Int {
|
||||||
return getChildAdapterPosition(findChildViewUnder(x, y) ?: return RecyclerView.NO_POSITION)
|
return getChildAdapterPosition(findChildViewUnder(x, y) ?: return RecyclerView.NO_POSITION)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RecyclerView.findFirstVisibleViewPosition(): Int {
|
fun RecyclerView.findFirstVisibleViewPosition(): Int {
|
||||||
@@ -21,7 +23,7 @@ fun RecyclerView.findFirstVisibleViewPosition(): Int {
|
|||||||
|
|
||||||
fun RecyclerView.findLastVisibleViewPosition(): Int {
|
fun RecyclerView.findLastVisibleViewPosition(): Int {
|
||||||
var pos = -1
|
var pos = -1
|
||||||
if ( layoutManager is LinearLayoutManager) {
|
if (layoutManager is LinearLayoutManager) {
|
||||||
pos = (layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
|
pos = (layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
|
||||||
}
|
}
|
||||||
return pos
|
return pos
|
||||||
|
|||||||
Reference in New Issue
Block a user