1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-11 02:50:28 +08:00
新增
1. CardFlow页面加载进度
修复
1. 进入漫画详情后,立即返回闪退
2. 分类切换标签闪退 (fix #56)
3. 我的下载某些漫画排序错误
4. 下载页缺失的图无法自动补齐
优化
1. 我的下载的加载速度
2. 进一步协程化(MPFT)
This commit is contained in:
源文雨
2024-03-12 18:26:00 +09:00
parent f13c2d32e6
commit 3dff5312ba
17 changed files with 325 additions and 261 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 50 versionCode 51
versionName '2.2.2' versionName '2.2.3'
resourceConfigurations += ['zh', 'zh-rCN'] resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -54,12 +54,8 @@ class Book(val path: String, private val getString: (Int) -> String, private val
val json get() = mJsonString val json get() = mJsonString
constructor(name: String, getString: (Int) -> String, exDir: File): this( constructor(name: String, getString: (Int) -> String, exDir: File): this(
Gson().fromJson(File(File(exDir, name), "info.json").readText(), Array<VolumeStructure>::class.java).let{ Reader.getComicPathWordInFolder(File(exDir, name)),
if (it.isEmpty() || it[0].results.list.isEmpty()) { getString, exDir, true, name
throw IllegalArgumentException("$name/info.json无效")
}
it[0].results.list[0].comic_path_word
}, getString, exDir, true, name
) )
/** /**
@@ -119,6 +115,7 @@ class Book(val path: String, private val getString: (Int) -> String, private val
saveVolumes(volumes) saveVolumes(volumes)
mVolumes = volumes mVolumes = volumes
} }
goSaveHead(isDownload)
whenFinish() whenFinish()
} }
} }
@@ -130,10 +127,18 @@ class Book(val path: String, private val getString: (Int) -> String, private val
mJsonString = Gson().toJson(volumes) mJsonString = Gson().toJson(volumes)
File(mangaFolder, "info.json").writeText(mJsonString) File(mangaFolder, "info.json").writeText(mJsonString)
File(mangaFolder, "grps.json").writeText(Gson().toJson(mKeys)) File(mangaFolder, "grps.json").writeText(Gson().toJson(mKeys))
(cover?.let { CMApi.imageProxy?.wrap(it) } ?:cover)?.let { }
}
private fun goSaveHead(force: Boolean) {
name?.let { name ->
val mangaFolder = File(exDir, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
val f = File(mangaFolder, "head.jpg")
if(force || !f.exists()) (cover?.let { CMApi.imageProxy?.wrap(it) } ?:cover)?.let {
Thread { Thread {
DownloadTools.getHttpContent(it, -1)?.let { data -> DownloadTools.getHttpContent(it, -1)?.let { data ->
File(mangaFolder, "head.jpg").writeBytes(data) f.writeBytes(data)
} }
}.start() }.start()
} }

View File

@@ -11,7 +11,7 @@ import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import java.io.File import java.io.File
object Reader { object Reader {
fun viewMangaAt(name: String, pos: Int, urlArray: Array<String>, fromFirstPage: Boolean = false) { fun start2viewManga(name: String, pos: Int, urlArray: Array<String>, fromFirstPage: Boolean = false) {
Log.d("MyR", "viewMangaAt name $name, pos $pos") Log.d("MyR", "viewMangaAt name $name, pos $pos")
mainWeakReference?.get()?.apply { mainWeakReference?.get()?.apply {
getPreferences(Context.MODE_PRIVATE)?.edit { getPreferences(Context.MODE_PRIVATE)?.edit {
@@ -39,7 +39,7 @@ object Reader {
} }
} }
} }
fun getComicPathWordInFile(file: File): String { fun getComicPathWordInFolder(file: File): String {
if(!file.exists()) { if(!file.exists()) {
return "N/A:!file.exists()" return "N/A:!file.exists()"
} }

View File

@@ -4,22 +4,26 @@ import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.liaoinstan.springview.widget.SpringView import com.liaoinstan.springview.widget.SpringView
import kotlinx.android.synthetic.main.line_header.view.* import kotlinx.android.synthetic.main.line_header.view.*
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.template.ui.CardList import top.fumiama.copymanga.template.ui.CardList
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true, val forceLoad: Boolean = false) : NoBackRefreshFragment(inflateRes) { open class MangaPagesFragmentTemplate(inflateRes:Int, private val isLazy: Boolean = true, val forceLoad: Boolean = false) : NoBackRefreshFragment(inflateRes) {
var cardPerRow = 3 var cardPerRow = 3
var cardWidth = 0 var cardWidth = 0
var cardHeight = 0 var cardHeight = 0
@@ -64,12 +68,12 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true
findNavController().popBackStack() findNavController().popBackStack()
return return
} }
Thread { lifecycleScope.launch {
sleep(600) withContext(Dispatchers.IO) {
activity?.runOnUiThread { delay(600)
setLayouts() setLayouts()
} }
}.start() }
} }
} }
@@ -80,60 +84,88 @@ open class MangaPagesFragmentTemplate(inflateRes:Int, val isLazy: Boolean = true
//jsonReaderNow = null //jsonReaderNow = null
} }
open fun setLayouts() { open suspend fun setLayouts() = withContext(Dispatchers.IO) {
val toolsBox = this.context?.let { UITools(it) } val toolsBox = this@MangaPagesFragmentTemplate.context?.let { UITools(it) }
val widthData = toolsBox?.calcWidthFromDp(8, 135) val widthData = toolsBox?.calcWidthFromDp(8, 135)
cardPerRow = widthData?.get(0) ?: 3 cardPerRow = widthData?.get(0) ?: 3
cardWidth = widthData?.get(2) ?: 128 cardWidth = widthData?.get(2) ?: 128
cardHeight = (cardWidth / 0.75 + 0.5).toInt() cardHeight = (cardWidth / 0.75 + 0.5).toInt()
mysp.footerView.lht.text = "加载" withContext(Dispatchers.Main){
mysp.headerView.lht.text = "刷新" mysp.footerView.lht.text = "加载"
mysp.headerView.lht.text = "刷新"
mydll?.setPadding(0, 0, 0, navBarHeight)
}
Log.d("MyMPAT", "Card per row: $cardPerRow") Log.d("MyMPAT", "Card per row: $cardPerRow")
Log.d("MyMPAT", "Card width: $cardWidth") Log.d("MyMPAT", "Card width: $cardWidth")
initCardList(WeakReference(this@MangaPagesFragmentTemplate))
mydll?.setPadding(0, 0, 0, navBarHeight)
initCardList(WeakReference(this))
managePage() managePage()
setListeners() setListeners()
//mypl.visibility = View.GONE
} }
private fun managePage() { private fun managePage() {
addPage() lifecycleScope.launch { addPage() }
if (isLazy) mysp.setListener(object : SpringView.OnFreshListener { if (isLazy) {
override fun onLoadmore() { mysp.apply {
addPage() post {
setListener(object : SpringView.OnFreshListener {
override fun onLoadmore() {
lifecycleScope.launch {
addPage()
}
}
override fun onRefresh() {
lifecycleScope.launch {
withContext(Dispatchers.IO) {
reset()
delay(600)
}
addPage()
}
}
})
}
} }
override fun onRefresh() { }
reset()
Thread {
sleep(600)
activity?.runOnUiThread {
addPage()
}
}.start()
}
})
} }
open fun addPage() {} open suspend fun addPage() {}
open fun onLoadFinish() { open suspend fun onLoadFinish() = withContext(Dispatchers.Main) {
//myp?.visibility = View.GONE mypc?.visibility = View.GONE
mysp?.onFinishFreshAndLoad() mysp?.onFinishFreshAndLoad()
//mys?.fullScroll(ScrollView.FOCUS_UP) //mys?.fullScroll(ScrollView.FOCUS_UP)
} }
open fun reset() { open suspend fun reset() = withContext(Dispatchers.Main) {
mydll.removeAllViews() mydll.removeAllViews()
isEnd = false isEnd = false
page = 0 page = 0
cardList?.reset() cardList?.reset()
mypl?.visibility = View.VISIBLE mypc?.visibility = View.VISIBLE
mypl?.progress = 0
} }
open fun initCardList(weakReference: WeakReference<Fragment>) {} open fun initCardList(weakReference: WeakReference<Fragment>) {}
open fun setListeners() {} open fun setListeners() {}
}
fun setProgress(p: Int) {
var newP = p
mypl?.post {
if (p == mypl?.progress) return@post
if (newP >= 100) {
Log.d("MyMPFT", "set 100, hide")
mypc?.visibility = View.GONE
return@post
}
else if (newP < 0) newP = 0
mypl?.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
setProgress(newP, true)
} else progress = newP
invalidate()
Log.d("MyMPFT", "set ${mypl?.progress}")
}
}
}
}

View File

@@ -108,7 +108,7 @@ class CardList(
val file = File(that?.context?.getExternalFilesDir(""), card.name) val file = File(that?.context?.getExternalFilesDir(""), card.name)
if(exitCardList) return@withIO if(exitCardList) return@withIO
cardFrame.let { cardFrame.let {
withContext(Dispatchers.Main) { it.tic.text = name } it.tic.apply { post { text = name } }
if(!file.exists()) { if(!file.exists()) {
if(head != null) { if(head != null) {
that?.context?.let { context -> that?.context?.let { context ->
@@ -119,33 +119,35 @@ class CardList(
if (exitCardList) return@GlideHideLottieViewListener if (exitCardList) return@GlideHideLottieViewListener
cardLoadingWaits.decrementAndGet() cardLoadingWaits.decrementAndGet()
}) })
withContext(Dispatchers.Main) { if (waitMillis > 0) it.imic.postDelayed({
if (waitMillis > 0) it.imic.postDelayed({ if (exitCardList) return@postDelayed
if (exitCardList) return@postDelayed g.into(it.imic)
g.into(it.imic) }, waitMillis) else it.imic.post { g.into(it.imic) }
}, waitMillis) else g.into(it.imic) }
} else {
it.laic.apply {
post {
pauseAnimation()
visibility = View.GONE
} }
} }
} else withContext(Dispatchers.Main) { it.imic.apply { post { setImageResource(R.drawable.img_defmask) } }
it.laic.pauseAnimation()
it.laic.visibility = View.GONE
it.imic.setImageResource(R.drawable.img_defmask)
} }
} else { } else {
val img = File(file, "head.jpg") val img = File(file, "head.jpg")
withContext(Dispatchers.Main) { it.laic.apply {
it.laic.pauseAnimation() post {
it.laic.visibility = View.GONE pauseAnimation()
visibility = View.GONE
}
} }
if(img.exists()) { if(img.exists()) {
withContext(Dispatchers.Main) { it.imic.apply {
it.imic.setImageURI(Uri.fromFile(img)) post {
setImageURI(Uri.fromFile(img))
}
} }
} else { } else it.imic.apply { post { setImageResource(R.drawable.img_defmask) } }
withContext(Dispatchers.Main) {
it.imic.setImageResource(R.drawable.img_defmask)
}
}
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if(card.isFinish) it.sgnic.visibility = View.VISIBLE if(card.isFinish) it.sgnic.visibility = View.VISIBLE

View File

@@ -7,8 +7,10 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.BookListStructure import top.fumiama.copymanga.json.BookListStructure
import top.fumiama.copymanga.json.HistoryBookListStructure import top.fumiama.copymanga.json.HistoryBookListStructure
import top.fumiama.copymanga.json.ShelfStructure import top.fumiama.copymanga.json.ShelfStructure
@@ -24,8 +26,9 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
private val subUrl get() = getApiUrl() private val subUrl get() = getApiUrl()
var ad: PausableDownloader? = null var ad: PausableDownloader? = null
override fun addPage() { override suspend fun addPage(): Unit = withContext(Dispatchers.IO) {
super.addPage() super.addPage()
setProgress(20)
ad = PausableDownloader(subUrl) { data -> ad = PausableDownloader(subUrl) { data ->
if(isRefresh) { if(isRefresh) {
page = 0 page = 0
@@ -37,15 +40,18 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
Log.d("MyICL", "offset:${results.offset}, total:${results.total}") Log.d("MyICL", "offset:${results.offset}, total:${results.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
if(code == 200) { if(code == 200) {
results.list.forEach { book -> val size = results?.list?.size?:0
results.list.forEachIndexed { i, book ->
Log.d("MyICL", "load @ $i")
if(ad?.exit == true) return@PausableDownloader if(ad?.exit == true) return@PausableDownloader
cardList?.addCard( cardList?.addCard(
book?.comic?.name?:"null", null, book?.comic?.cover, book?.comic?.name?:"null", null, book?.comic?.cover,
book?.comic?.path_word, null, null, book?.comic?.path_word, null, null,
isFinish = false, isNew = false isFinish = false, isNew = false
) )
setProgress(20+80*i/size)
} }
offset += results.list.size offset += size
} }
} }
page++ page++
@@ -56,15 +62,18 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
if(code == 200) { if(code == 200) {
results?.list?.forEach{ book -> val size = results?.list?.size?:0
results?.list?.forEachIndexed { i, book ->
Log.d("MyICL", "load @ $i")
if(ad?.exit == true) return@PausableDownloader if(ad?.exit == true) return@PausableDownloader
cardList?.addCard( cardList?.addCard(
book?.comic?.name?:"null", "\n云读至${book?.last_chapter_name}", book?.comic?.cover, book?.comic?.name?:"null", "\n云读至${book?.last_chapter_name}", book?.comic?.cover,
book?.comic?.path_word, null, null, book?.comic?.path_word, null, null,
book?.comic?.status==1 book?.comic?.status==1
) )
setProgress(20+80*i/size)
} }
offset += results.list.size offset += size
} }
} }
page++ page++
@@ -75,7 +84,9 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
if(code == 200) { if(code == 200) {
results?.list?.forEach{ book -> val size = results?.list?.size?:0
results?.list?.forEachIndexed { i, book ->
Log.d("MyICL", "load @ $i")
if(ad?.exit == true) return@PausableDownloader if(ad?.exit == true) return@PausableDownloader
cardList?.addCard( cardList?.addCard(
book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover, book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover,
@@ -83,8 +94,9 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
book?.comic?.status==1, book?.comic?.status==1,
book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id
) )
setProgress(20+80*i/size)
} }
offset += results.list.size offset += size
} }
} }
page++ page++
@@ -95,11 +107,14 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}")
if(results.offset < results.total) { if(results.offset < results.total) {
if(code == 200) { if(code == 200) {
results?.list?.forEach{ book -> val size = results?.list?.size?:0
results?.list?.forEachIndexed { i, book ->
Log.d("MyICL", "load @ $i")
if(ad?.exit == true) return@PausableDownloader if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(book?.name?:"null", null, book?.cover, book?.path_word, null, null, false) cardList?.addCard(book?.name?:"null", null, book?.cover, book?.path_word, null, null, false)
setProgress(20+80*i/size)
} }
offset += results.list.size offset += size
} }
} }
page++ page++
@@ -107,17 +122,18 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
} }
onLoadFinish() onLoadFinish()
} }
lifecycleScope.launch { try {
ad?.run()
} catch (e: Exception) {
e.printStackTrace()
try { try {
ad?.run() withContext(Dispatchers.Main) {
} catch (e: Exception) {
e.printStackTrace()
try {
findNavController().popBackStack() findNavController().popBackStack()
} catch (_: Exception) {} }
} } catch (_: Exception) {}
} }
} }
override fun initCardList(weakReference: WeakReference<Fragment>) { override fun initCardList(weakReference: WeakReference<Fragment>) {
super.initCardList(weakReference) super.initCardList(weakReference)
cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow) cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)
@@ -136,14 +152,11 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
return "" return ""
} }
override fun onLoadFinish() { override suspend fun onLoadFinish() {
super.onLoadFinish() if(ad?.exit != true) super.onLoadFinish()
activity?.runOnUiThread {
if(ad?.exit != true) mypl.visibility = View.GONE
}
} }
override fun reset() { override suspend fun reset() {
super.reset() super.reset()
offset = 0 offset = 0
} }
@@ -162,4 +175,14 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
super.onDestroy() super.onDestroy()
ad?.exit = true ad?.exit = true
} }
fun delayedRefresh(timeMillis: Long) {
lifecycleScope.launch {
withContext(Dispatchers.IO) {
delay(timeMillis)
reset()
addPage()
}
}
}
} }

View File

@@ -3,6 +3,8 @@ package top.fumiama.copymanga.template.ui
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.view.View import android.view.View
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
@@ -25,40 +27,32 @@ open class StatusCardFlow(private val api: Int, nav: Int, inflateRes: Int,
override fun setListeners() { override fun setListeners() {
super.setListeners() super.setListeners()
lineUpdate?.let { setUpdate(it) } lineUpdate?.apply { post {
lineHot?.let { setHot(it) } setUpdate(this)
lineUpdate?.alpha = 1f alpha = 1f
lineHot?.alpha = 0.5f } }
lineHot?.apply { post {
setHot(this)
alpha = 0.5f
} }
} }
open fun setUpdate(that: View) { private fun setUpdate(that: View) {
that.apply { that.apply {
apt.setText(R.string.menu_update_time) apt.setText(R.string.menu_update_time)
setOnClickListener { setOnClickListener {
sortValue = triggerLine(false) sortValue = triggerLine(false)
Thread{ delayedRefresh(400)
Thread.sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
} }
} }
} }
open fun setHot(that: View) { private fun setHot(that: View) {
that.apply { that.apply {
apt.setText(R.string.menu_hot) apt.setText(R.string.menu_hot)
setOnClickListener { setOnClickListener {
sortValue = triggerLine(true) sortValue = triggerLine(true)
Thread { delayedRefresh(400)
Thread.sleep(400)
activity?.runOnUiThread {
reset()
addPage()
}
}.start()
} }
} }
} }

View File

@@ -68,6 +68,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
book?.updateInfo() book?.updateInfo()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
if(mBookHandler?.exit != false) return@launch
Toast.makeText(context, R.string.null_book, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.null_book, Toast.LENGTH_SHORT).show()
findNavController().popBackStack() findNavController().popBackStack()
return@launch return@launch
@@ -82,6 +83,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
if(mBookHandler?.exit != false) return@launch
Toast.makeText(context, R.string.null_volume, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.null_volume, Toast.LENGTH_SHORT).show()
findNavController().popBackStack() findNavController().popBackStack()
return@launch return@launch
@@ -126,7 +128,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
} }
setOnClickListener { setOnClickListener {
mBookHandler?.urlArray?.let { mBookHandler?.urlArray?.let {
Reader.viewMangaAt(name, i, it) Reader.start2viewManga(name, i, it)
} }
} }
} }

View File

@@ -210,7 +210,7 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
Log.d("MyBH", "add last single chapter ${it.name}") Log.d("MyBH", "add last single chapter ${it.name}")
val index = i val index = i
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) }
} }
line?.let { l -> addVolumesView(fbl, l) } line?.let { l -> addVolumesView(fbl, l) }
} else { } else {
@@ -219,14 +219,14 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
lct.text = it.name lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i val index = i
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) }
} }
} }
} else line?.l2cr?.apply { } else line?.l2cr?.apply {
lct.text = it.name lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i val index = i
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) }
line?.let { l -> addVolumesView(fbl, l) } line?.let { l -> addVolumesView(fbl, l) }
line = null line = null
} }

View File

@@ -1,19 +1,15 @@
package top.fumiama.copymanga.ui.cardflow.rank package top.fumiama.copymanga.ui.cardflow.rank
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_rank.* import kotlinx.android.synthetic.main.fragment_rank.*
import kotlinx.android.synthetic.main.line_rank.view.* import kotlinx.android.synthetic.main.line_rank.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ExperimentalStdlibApi @ExperimentalStdlibApi
@@ -45,7 +41,7 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
ad?.exit = true ad?.exit = true
} }
override fun onLoadFinish() { override suspend fun onLoadFinish() {
super.onLoadFinish() super.onLoadFinish()
isLoading = false isLoading = false
} }
@@ -65,43 +61,36 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
override fun onTabSelected(tab: TabLayout.Tab?) { override fun onTabSelected(tab: TabLayout.Tab?) {
sortValue = tab?.position?:0 sortValue = tab?.position?:0
if(!isLoading) delayedRefresh() if(!isLoading) {
isLoading = true
delayedRefresh(400)
}
} }
override fun onTabUnselected(tab: TabLayout.Tab?) {} override fun onTabUnselected(tab: TabLayout.Tab?) {}
}) })
} }
private fun delayedRefresh() {
lifecycleScope.launch {
isLoading = true
withContext(Dispatchers.IO) {
delay(400)
withContext(Dispatchers.Main) {
reset()
addPage()
}
}
}
}
fun showSexInfo(toolsBox: UITools) { fun showSexInfo(toolsBox: UITools) {
if (ad?.exit != false) return if (ad?.exit != false) return
toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型", toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型",
"男频", "全部", "女频", { "男频", "全部", "女频", {
if(!isLoading) { if(!isLoading) {
audience = 1 audience = 1
delayedRefresh() isLoading = true
delayedRefresh(400)
} }
}, { }, {
if(!isLoading) { if(!isLoading) {
audience = 0 audience = 0
delayedRefresh() isLoading = true
delayedRefresh(400)
} }
}, { }, {
if(!isLoading) { if(!isLoading) {
audience = 2 audience = 2
delayedRefresh() isLoading = true
delayedRefresh(400)
} }
}) })
} }

View File

@@ -1,8 +1,5 @@
package top.fumiama.copymanga.ui.cardflow.recommend package top.fumiama.copymanga.ui.cardflow.recommend
import android.view.View
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R

View File

@@ -3,19 +3,15 @@ package top.fumiama.copymanga.ui.cardflow.shelf
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_shelf.* import kotlinx.android.synthetic.main.line_shelf.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
@ExperimentalStdlibApi @ExperimentalStdlibApi
class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_sub_to_nav_book, isShelfBook = true) { class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_sub_to_nav_book, isShelfBook = true) {
@@ -56,7 +52,7 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
val same = sortValue in 0..1 val same = sortValue in 0..1
sortValue = rotate(it.apim, same, 0) sortValue = rotate(it.apim, same, 0)
if (!same) fade() if (!same) fade()
resetDelayed() delayedRefresh(400)
} }
} }
@@ -67,7 +63,7 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
val same = sortValue in 2..3 val same = sortValue in 2..3
sortValue = rotate(it.apim, same, 2) sortValue = rotate(it.apim, same, 2)
if (!same) fade() if (!same) fade()
resetDelayed() delayedRefresh(400)
} }
} }
@@ -78,7 +74,7 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
val same = sortValue>=4 val same = sortValue>=4
sortValue = rotate(it.apim, same, 4) sortValue = rotate(it.apim, same, 4)
if (!same) fade() if (!same) fade()
resetDelayed() delayedRefresh(400)
} }
} }
@@ -119,16 +115,4 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su
} }
} }
} }
private fun resetDelayed() {
lifecycleScope.launch {
withContext(Dispatchers.IO) {
delay(400)
withContext(Dispatchers.Main) {
reset()
addPage()
}
}
}
}
} }

View File

@@ -8,7 +8,6 @@ import com.google.gson.Gson
import kotlinx.android.synthetic.main.anchor_popular.view.* import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_sort.* import kotlinx.android.synthetic.main.line_sort.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.FilterStructure import top.fumiama.copymanga.json.FilterStructure
@@ -17,7 +16,6 @@ import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.template.ui.StatusCardFlow import top.fumiama.copymanga.template.ui.StatusCardFlow
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
@ExperimentalStdlibApi @ExperimentalStdlibApi
class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layout.fragment_sort) { class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layout.fragment_sort) {
@@ -30,8 +28,8 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
CMApi.myHostApiUrl, CMApi.myHostApiUrl,
page * 21, page * 21,
sortWay[sortValue], sortWay[sortValue],
if(theme >= 0) (filter?.results?.theme?.get(theme)?.path_word ?: "") else "", if(theme >= 0 && theme < (filter?.results?.theme?.size ?: 0)) (filter?.results?.theme?.get(theme)?.path_word ?: "") else "",
if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: "") else "", if(region >= 0 && region < (filter?.results?.top?.size ?: 0)) (filter?.results?.top?.get(region)?.path_word ?: "") else "",
) )
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -60,26 +58,18 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
private fun setClasses() { private fun setClasses() {
filter?.results?.top?.let { items -> filter?.results?.top?.let { items ->
setMenu(items, line_sort_region) setMenu(items, line_sort_region) {
region = it
}
} }
filter?.results?.theme?.let { items -> filter?.results?.theme?.let { items ->
setMenu(items, line_sort_class) setMenu(items, line_sort_class) {
} theme = it
}
private fun suspendReset() {
lifecycleScope.launch {
withContext(Dispatchers.IO) {
delay(400)
withContext(Dispatchers.Main) {
reset()
addPage()
}
} }
} }
} }
private fun setMenu(items: Array<out ThemeStructure>, line: View) { private fun setMenu(items: Array<out ThemeStructure>, line: View, setIndex: (Int) -> Unit) {
if(ad?.exit == true) return if(ad?.exit == true) return
line.apt.text = "全部" line.apt.text = "全部"
line.setOnClickListener { line.setOnClickListener {
@@ -90,9 +80,9 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
label = "全部" label = "全部"
labelColor = it.apt.currentTextColor labelColor = it.apt.currentTextColor
callback = { callback = {
region = -1 setIndex(-1)
it.apt.text = "全部" it.apt.text = "全部"
suspendReset() delayedRefresh(400)
} }
} }
for(i in items.indices) item { for(i in items.indices) item {
@@ -100,8 +90,8 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
labelColor = it.apt.currentTextColor labelColor = it.apt.currentTextColor
callback = { //optional callback = { //optional
it.apt.text = label it.apt.text = label
region = i setIndex(i)
suspendReset() delayedRefresh(400)
} }
} }
} }

View File

@@ -8,8 +8,8 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.line_lazybooklines.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
@@ -19,10 +19,8 @@ import top.fumiama.copymanga.template.ui.CardList
import top.fumiama.copymanga.tools.file.FileUtils import top.fumiama.copymanga.tools.file.FileUtils
import top.fumiama.copymanga.tools.ui.Navigate import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
@@ -57,59 +55,89 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
exit = true exit = true
} }
override fun addPage() { override suspend fun addPage(): Unit = withContext(Dispatchers.IO) {
super.addPage() super.addPage()
if(isRefresh){ if(isRefresh){
page = 0 page = 0
isRefresh = false isRefresh = false
} }
lifecycleScope.launch { if (isEnd) {
withContext(Dispatchers.IO) { onLoadFinish()
if(!isEnd) { return@withContext
if(sortedBookList == null || isContentChanged) { }
Log.d("MyNDF", "Sorting books...") setProgress(20)
sortedBookList = extDir?.listFiles()?.sortedBy { if(sortedBookList == null || isContentChanged) {
return@sortedBy Reader.getComicPathWordInFile(it) Log.d("MyNDF", "Sorting books...")
} sortedBookList = extDir?.listFiles()?.toList()
if (isReverse) { var size = sortedBookList?.size?:0
Log.d("MyNDF", "reversed...") if (size > 0) {
sortedBookList = sortedBookList?.asReversed() if (isReverse) {
} Log.d("MyNDF", "reversed...")
if (!showAll) { sortedBookList = sortedBookList?.asReversed()
sortedBookList = sortedBookList?.filter { }
return@filter FileUtils.sizeOf(it) / 1048576 > 0 setProgress(40)
if (!showAll) {
val cache = hashMapOf<String, Boolean>()
sortedBookList = sortedBookList?.filter {
setProgress(40+20*cache.size/size)
it.absolutePath.let { path ->
if (cache.containsKey(path)) cache[path]!!
else {
val b = (it.listFiles { f ->
return@listFiles f.isDirectory && f.listFiles()?.isNotEmpty() ?: false
}?.size ?: 0) > 0
cache[path] = b
b
} }
} }
isContentChanged = false
}
Log.d("MyNDF", "Start drawing cards")
cardList?.addCard(oldDlCardName, path = oldDlCardName)
var cnt = 1
sortedBookList?.let {
for(i in it.listIterator(page)) {
if(cardList?.exitCardList != false) return@withContext
page++ // page is actually count
val chosenJson = File(i, "info.bin")
val newJson = File(i, "info.json")
val bookSize = (FileUtils.sizeOf(i)/1048576).toInt()
when {
chosenJson.exists() -> continue // unsupported old folder
newJson.exists() -> {
if(cardList?.exitCardList != false) return@withContext
cardList?.addCard(i.name, "\n${bookSize}MB")
cnt++
}
}
if (cnt >= 21) break
}
if(page >= it.size) {
isEnd = true
}
} }
} }
onLoadFinish() setProgress(60)
size = sortedBookList?.size?:0
val cache = hashMapOf<String, String>()
sortedBookList = sortedBookList?.sortedBy {
setProgress(60+20*cache.size/size)
return@sortedBy it.absolutePath.let { path ->
if (cache.containsKey(path)) cache[path]!!
else {
val s = Reader.getComicPathWordInFolder(it).lowercase()
cache[path] = s
s
}
}
}
setProgress(80)
}
isContentChanged = false
}
Log.d("MyNDF", "Start drawing cards")
cardList?.addCard(oldDlCardName, path = oldDlCardName)
var cnt = 1
val size = sortedBookList?.size?:0
sortedBookList?.let {
for(i in it.listIterator(page)) {
if(cardList?.exitCardList != false) return@withContext
page++ // page is actually count
val chosenJson = File(i, "info.bin")
val newJson = File(i, "info.json")
val bookSize = (FileUtils.sizeOf(i)/1048576).toInt()
when {
chosenJson.exists() -> continue // unsupported old folder
newJson.exists() -> {
if(cardList?.exitCardList != false) return@withContext
cardList?.addCard(i.name, "\n${bookSize}MB")
cnt++
}
}
setProgress(80+20*(cnt-1)/size)
if (cnt >= 21) break
}
if(page >= it.size) {
isEnd = true
} }
} }
setProgress(99)
onLoadFinish()
} }
override fun initCardList(weakReference: WeakReference<Fragment>) { override fun initCardList(weakReference: WeakReference<Fragment>) {
@@ -184,22 +212,17 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
"确定", null, "取消", { "确定", null, "取消", {
isReverse = !isReverse isReverse = !isReverse
isContentChanged = true isContentChanged = true
reset() lifecycleScope.launch {
Thread { withContext(Dispatchers.IO) {
sleep(600) reset()
addPage() delay(600)
}.start() addPage()
}
}
} }
) )
} }
override fun onLoadFinish() {
super.onLoadFinish()
activity?.runOnUiThread {
mypl.visibility = View.GONE
}
}
companion object { companion object {
var wn: WeakReference<NewDownloadFragment>? = null var wn: WeakReference<NewDownloadFragment>? = null
} }

View File

@@ -24,7 +24,7 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
@ExperimentalStdlibApi @ExperimentalStdlibApi
fun toPage(goNext:Boolean) { fun toPage(goNext:Boolean) {
v?.let { v -> v?.let { v ->
if (v.clicked) { if (v.clicked == 1) {
v.hideDrawer() v.hideDrawer()
return return
} }
@@ -48,7 +48,7 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
//if(v.zipFirst) intent.putExtra("callFrom", "zipFirst") //if(v.zipFirst) intent.putExtra("callFrom", "zipFirst")
v.tt.canDo = false v.tt.canDo = false
//ViewMangaActivity.dlhandler = null //ViewMangaActivity.dlhandler = null
comicName?.let { Reader.viewMangaAt(it, chapterPosition, v.urlArray, goNext) } comicName?.let { Reader.start2viewManga(it, chapterPosition, v.urlArray, goNext) }
v.finish() v.finish()
return return
} }
@@ -59,6 +59,11 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
} }
} }
fun toggleDrawer() { fun toggleDrawer() {
if (v?.clicked == false) v?.showDrawer() else v?.hideDrawer() v?.apply {
when(clicked) {
0 -> showDrawer()
1 -> hideDrawer()
}
}
} }
} }

View File

@@ -66,7 +66,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
var count = 0 var count = 0
private lateinit var handler: VMHandler private lateinit var handler: VMHandler
lateinit var tt: TimeThread lateinit var tt: TimeThread
var clicked = false var clicked = 0
private var isInSeek = false private var isInSeek = false
private var isInScroll = true private var isInScroll = true
//private var progressLog: PropertiesTools? = null //private var progressLog: PropertiesTools? = null
@@ -884,28 +884,38 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
fun showDrawer() { fun showDrawer() {
infseek.visibility = View.VISIBLE clicked = 2 // loading
isearch.visibility = View.VISIBLE infseek.post {
ObjectAnimator.ofFloat( infseek.visibility = View.VISIBLE
oneinfo, isearch.post {
"alpha", isearch.visibility = View.VISIBLE
oneinfo.alpha, infseek.invalidate()
1F isearch.invalidate()
).setDuration(233).start() ObjectAnimator.ofFloat(
clicked = true oneinfo,
"alpha",
oneinfo.alpha,
1F
).setDuration(300).start()
clicked = 1 // true
}
}
} }
fun hideDrawer() { fun hideDrawer() {
clicked = 2 // loading
ObjectAnimator.ofFloat( ObjectAnimator.ofFloat(
oneinfo, oneinfo,
"alpha", "alpha",
oneinfo.alpha, oneinfo.alpha,
0F 0F
).setDuration(233).start() ).setDuration(300).start()
clicked = false
infseek.postDelayed({ infseek.postDelayed({
infseek.visibility = View.GONE infseek.visibility = View.GONE
isearch.visibility = View.GONE isearch.visibility = View.GONE
infseek.invalidate()
isearch.invalidate()
clicked = 0 // false
}, 300) }, 300)
handler.sendEmptyMessage(if (fullyHideInfo) VMHandler.HIDE_INFO_CARD_FULL else VMHandler.HIDE_INFO_CARD) handler.sendEmptyMessage(if (fullyHideInfo) VMHandler.HIDE_INFO_CARD_FULL else VMHandler.HIDE_INFO_CARD)
} }

View File

@@ -25,18 +25,26 @@
android:id="@+id/mydll" android:id="@+id/mydll"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"/> android:orientation="vertical" />
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</com.liaoinstan.springview.widget.SpringView> </com.liaoinstan.springview.widget.SpringView>
<ProgressBar <androidx.cardview.widget.CardView
android:id="@+id/mypl" android:id="@+id/mypc"
style="?android:attr/progressBarStyle" android:layout_width="@dimen/book_card_width"
android:layout_width="wrap_content" android:layout_height="@dimen/icon_size_middle"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent">
<ProgressBar
android:id="@+id/mypl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="16dp"
style="?android:attr/progressBarStyleHorizontal"/>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>