1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-10 10:24:29 +08:00
新增
1. 支持无网络时从下载访问漫画详情页
修复
1. 保存封面超时时间过短
2. 竖向翻页回到上一段闪退
3. 无动画阅览时加载下一页闪屏
4. 排行页快速点击tab时显示错乱
优化
1. 我的下载页的无用代码
This commit is contained in:
源文雨
2024-03-11 02:55:36 +09:00
parent 335d860b0d
commit d60c8d96a4
18 changed files with 470 additions and 451 deletions

View File

@@ -287,16 +287,15 @@ class MainActivity : AppCompatActivity() {
}
private fun saveFile(uri: Uri) {
//val f = File(getExternalFilesDir(""), "headPic")
val fd = contentResolver.openFileDescriptor(uri, "r")
fd?.fileDescriptor?.let {
val fi = FileInputStream(it)
val fo = headPic.outputStream()
fi.copyTo(fo)
fi.close()
fo.close()
contentResolver.openFileDescriptor(uri, "r")?.use {
it.fileDescriptor?.let { fd ->
FileInputStream(fd).use { fi ->
headPic.outputStream().use { fo ->
fi.copyTo(fo)
}
}
}
}
fd?.close()
}
private fun checkHeadPicture() {
@@ -306,9 +305,9 @@ class MainActivity : AppCompatActivity() {
private var cropLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val fi = headPic.inputStream()
navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))
fi.close()
headPic.inputStream().use { fi ->
navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))
}
} else Toast.makeText(this, R.string.err_crop_img, Toast.LENGTH_SHORT).show()
}

View File

@@ -1,10 +1,169 @@
package top.fumiama.copymanga.manga
class Book(val pathWord: String, val readLocally: Boolean = false) {
/**
* 更新云端最新信息
*/
suspend fun update() {
import android.util.Log
import com.google.gson.Gson
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.line_booktandb.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.BookInfoStructure
import top.fumiama.copymanga.json.ThemeStructure
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R
import java.io.File
class Book(val path: String, private val getString: (Int) -> String, private val exDir: File, private val loadCache: Boolean = false, private val mPassName: String? = null) {
private val mBookApiUrl = getString(R.string.bookInfoApiUrl).format(CMApi.myHostApiUrl, path)
private val mUserAgent = getString(R.string.pc_ua)
private var mBook: BookInfoStructure? = null
private var mGroupPathWords = arrayOf<String>()
private var mKeys = arrayOf<String>()
private var mCounts = intArrayOf()
private var mVolumes = arrayOf<VolumeStructure>()
private var mJsonString = ""
var exit = false
val name: String? get() = mBook?.results?.comic?.name?:mPassName
val cover: String? get() = mBook?.results?.comic?.cover
val cachedCover: File?
get() {
val mangaFolder = name?.let { File(exDir, it) }?:return null
val head = File(mangaFolder, "head.jpg")
if (!head.exists()) return null
return head
}
val region get() = mBook?.results?.comic?.region?.display?:"未知"
val author: Array<ThemeStructure>? get() = mBook?.results?.comic?.author
val theme: Array<ThemeStructure>? get() = mBook?.results?.comic?.theme
val keys get() = mKeys
val imageType: String
get() = when(mBook?.results?.comic?.img_type) {
1 -> "条漫"
2 -> "普通"
else -> "未知类型${mBook?.results?.comic?.img_type}"
}
val popular get() = mBook?.results?.comic?.popular?:0
val status get() = mBook?.results?.comic?.status?.display?:"未知"
val updateTime get() = mBook?.results?.comic?.datetime_updated?:"未知"
val brief get() = mBook?.results?.comic?.brief?:"空简介"
val volumes get() = mVolumes
val uuid get() = mBook?.results?.comic?.uuid
val json get() = mJsonString
constructor(name: String, getString: (Int) -> String, exDir: File): this(
Gson().fromJson(File(File(exDir, name), "info.json").readText(), Array<VolumeStructure>::class.java).let{
if (it.isEmpty() || it[0].results.list.isEmpty()) {
throw IllegalArgumentException("$name/info.json无效")
}
it[0].results.list[0].comic_path_word
}, getString, exDir, true, name
)
/**
* 更新云端最新图书信息并缓存到本地
*/
suspend fun updateInfo() = withContext(Dispatchers.IO) {
try {
var isDownload = false
val data: ByteArray = if (loadCache) {
name?.let { loadInfo(it) } ?: run {
isDownload = true
DownloadTools.getHttpContent(mBookApiUrl, null, mUserAgent)
}
} else {
isDownload = true
DownloadTools.getHttpContent(mBookApiUrl, null, mUserAgent)
}
mBook = data.inputStream().use {
Gson().fromJson(it.reader(), BookInfoStructure::class.java)
}
if (isDownload) saveInfo(data)
mGroupPathWords = arrayOf()
mKeys = arrayOf()
mCounts = intArrayOf()
mBook?.results?.groups?.values?.forEach {
mKeys += it.name
mGroupPathWords += it.path_word
if (it.count == 0) {
it.count = 1
}
mCounts += it.count
Log.d("MyB", "Add caption: ${it.name} @ ${it.path_word} of ${it.count}")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
/**
* 更新云端最新章节信息并缓存到本地
*/
suspend fun updateVolumes(whenFinish: suspend () -> Unit) = withContext(Dispatchers.IO) withIO@ {
var isDownload = false
var volumes = if(loadCache && loadVolumes()) mVolumes else emptyArray<VolumeStructure>()
if(volumes.isEmpty()) {
isDownload = true
mGroupPathWords.forEachIndexed { i, g ->
Volume(path, g, getString) {
return@Volume exit
}.updateChapters(mCounts[i])?.let { volumes += it }
}
}
if (!exit && volumes.size == mGroupPathWords.size) {
if(isDownload) {
saveVolumes(volumes)
mVolumes = volumes
}
whenFinish()
}
}
private suspend fun saveVolumes(volumes: Array<VolumeStructure>) = withContext(Dispatchers.IO) {
name?.let { name ->
val mangaFolder = File(exDir, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
mJsonString = Gson().toJson(volumes)
File(mangaFolder, "info.json").writeText(mJsonString)
File(mangaFolder, "grps.json").writeText(Gson().toJson(mKeys))
(cover?.let { CMApi.proxy?.wrap(it) } ?:cover)?.let {
DownloadTools.getHttpContent(it, null, mUserAgent)
}?.let { data ->
File(mangaFolder, "head.jpg").writeBytes(data)
}
}
}
private suspend fun loadVolumes(): Boolean = withContext(Dispatchers.IO) {
name?.let { name ->
val mangaFolder = File(exDir, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
val jsonFile = File(mangaFolder, "info.json")
if (!jsonFile.exists()) return@let false
mJsonString = jsonFile.readText()
mVolumes = Gson().fromJson(mJsonString, Array<VolumeStructure>::class.java)
val groupFile = File(mangaFolder, "grps.json")
if (!groupFile.exists()) return@let false
groupFile.inputStream().use {
mKeys = Gson().fromJson(it.reader(), Array<String>::class.java)
}
return@let true
}?:false
}
private suspend fun saveInfo(data: ByteArray) = withContext(Dispatchers.IO) {
name?.let { name ->
val mangaFolder = File(exDir, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
File(mangaFolder, "meta.json").writeBytes(data)
}
}
private suspend fun loadInfo(name: String): ByteArray? = withContext(Dispatchers.IO) {
val mangaFolder = File(exDir, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
val f = File(mangaFolder, "meta.json")
if (!f.exists()) return@withContext null
return@withContext f.readBytes()
}
}

View File

@@ -0,0 +1,76 @@
package top.fumiama.copymanga.manga
import android.util.Log
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.ChapterStructure
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
class Volume(private val path: String, private val groupPathWord: String, getString: (Int) -> String, private val isExit: ()->Boolean) {
private val mGroupInfoApiUrlTemplate = getString(R.string.groupInfoApiUrl)
private val exit: Boolean
get() {
if (!isExit()) return false
// destroy
mDownloaders.forEach { it.exit = true }
return true
}
private var mDownloaders = arrayOf<PausableDownloader>()
private var mVolume: VolumeStructure? = null
suspend fun updateChapters(count: Int): VolumeStructure? = withContext(Dispatchers.IO) {
val times = count / 100
val remain = count % 100
val re = arrayOfNulls<VolumeStructure>(if(remain != 0) (times+1) else (times))
if (re.isEmpty()) return@withContext null
Log.d("MyV", "${groupPathWord}卷共需加载${if(times == 0) 1 else times}")
download(re, 0, count)
return@withContext mVolume
}
private fun getApiUrl(offset: Int) = mGroupInfoApiUrlTemplate.format(CMApi.myHostApiUrl, path, groupPathWord, offset)
private suspend fun download(re: Array<VolumeStructure?>, offset: Int, c: Int) = withContext(Dispatchers.IO) {
Log.d("MyV", "下载偏移: $offset")
getApiUrl(offset).let {
if (exit) return@withContext
val ad = PausableDownloader(it, whenFinish = whenFinish(re, c-100, offset+100))
mDownloaders += ad
ad.run()
}
}
private fun whenFinish(re: Array<VolumeStructure?>, c: Int, offset: Int): suspend (ByteArray) -> Unit = lambda@ { result: ByteArray ->
try {
val r = Gson().fromJson(result.decodeToString(), VolumeStructure::class.java)
val o = r.results.offset / 100
re[o] = r
Log.d("MyV", "获得${groupPathWord}卷的${r.results.list.size}章内容, 偏移$o*100=${r.results.offset}, 共${re.size}")
if (c > 0) {
download(re, offset, c)
return@lambda
}
if (re.any { it == null }) { // have uncompleted items
Log.d("MyV", "下载未完成, 存在空卷")
return@lambda
}
if(re.isNotEmpty()) { // safer check, likely
re[0]?.let {
var s = emptyArray<ChapterStructure>()
re.forEach { v ->
v?.results?.list?.forEach { chapter ->
s += chapter
}
}
it.results?.list = s
}
mVolume = re[0]
}
return@lambda
} catch (e: Exception) {
e.printStackTrace()
return@lambda
}
}
}

View File

@@ -71,13 +71,13 @@ open class AutoDownloadHandler(
cacheFile?.let {
if (it.exists()) {
var pass = true
val fi = it.inputStream()
try {
pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass))
} catch (e: Exception) {
e.printStackTrace()
it.inputStream().use { fi->
try {
pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass))
} catch (e: Exception) {
e.printStackTrace()
}
}
fi.close()
if (pass) return@withContext
}
}

View File

@@ -9,16 +9,17 @@ import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import kotlin.random.Random
class PausableDownloader(private val url: String, private val waitMilliseconds: Long = 0, private val whenFinish: suspend (result: ByteArray)->Unit) {
class PausableDownloader(private val url: String, private val waitMilliseconds: Long = 0, private val whenFinish: (suspend (result: ByteArray)->Unit)? = null) {
var exit = false
suspend fun run() = withContext(Dispatchers.IO) {
var c = 0
while (!exit && c++ < 3) {
try {
whenFinish(DownloadTools.getHttpContent(url,
val data = (DownloadTools.getHttpContent(url,
mainWeakReference?.get()?.getString(R.string.referer)!!,
mainWeakReference?.get()?.getString(R.string.pc_ua)!!
))
whenFinish?.let { it(data) }
break
} catch (e: Exception) {
e.printStackTrace()

View File

@@ -25,10 +25,10 @@ class PropertiesTools(private val f: File):Properties() {
private fun createNew(f: File) {
f.createNewFile()
val o = f.outputStream()
this.storeToXML(o, "store")
f.outputStream().use { o ->
this.storeToXML(o, "store")
}
Log.d("MyPT", "Generate new prop.")
o.close()
}
private fun loadFromXml(`in`: InputStream?): PropertiesTools {
@@ -44,20 +44,20 @@ class PropertiesTools(private val f: File):Properties() {
operator fun get(key: String): String{
return if(cache.containsKey(key)) cache[key]?:"null"
else {
val i = f.inputStream()
val re = this.loadFromXml(i).getProperty(key)?:"null"
Log.d("MyPT", "Read $key = $re")
i.close()
cache[key] = re
re
f.inputStream().use { i ->
val re = this.loadFromXml(i).getProperty(key)?:"null"
Log.d("MyPT", "Read $key = $re")
cache[key] = re
re
}
}
}
operator fun set(key: String, value: String) {
cache[key] = value
val o = f.outputStream()
this.setProp(key, value).storeToXML(o, "store")
f.outputStream().use { o ->
this.setProp(key, value).storeToXML(o, "store")
}
Log.d("MyPT", "Set $key = $value")
o.close()
}
}

View File

@@ -8,31 +8,27 @@ import android.view.View
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.fragment_book.*
import kotlinx.android.synthetic.main.line_bookinfo_text.*
import kotlinx.android.synthetic.main.line_booktandb.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.manga.Book
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.general.NoBackRefreshFragment
import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicReference
class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
var isOnPause = false
var book: Book? = null
private var mBookHandler: BookHandler? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -40,37 +36,48 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
fbvp?.setPadding(0, 0, 0, navBarHeight)
if(isFirstInflate) {
var path = ""
arguments?.apply {
if (getBoolean("loadJson")) {
getString("name")?.let { name ->
activity?.getExternalFilesDir("")?.let {
Gson().fromJson(File(File(it, name), "info.json").readText(), Array<VolumeStructure>::class.java)
}?.apply {
if (isEmpty() || get(0).results.list.isEmpty()) {
findNavController().popBackStack()
return
}
else {
path = get(0).results.list[0].comic_path_word
}
try {
book = Book(name, {
return@Book getString(it)
}, activity?.getExternalFilesDir("")!!)
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(context, R.string.null_book, Toast.LENGTH_SHORT).show()
findNavController().popBackStack()
return
}
}
} else getString("path").let {
if (it != null) path = it
if (it != null) book = Book(it, { id ->
return@Book getString(id)
}, activity?.getExternalFilesDir("")!!, false)
else {
findNavController().popBackStack()
return
}
}
}
mBookHandler = BookHandler(WeakReference(this), path)
Log.d("MyBF", "read path: $path")
mBookHandler = BookHandler(WeakReference(this))
bookHandler.set(mBookHandler)
lifecycleScope.launch {
withContext(Dispatchers.IO) {
sleep(600)
mBookHandler?.startLoad()
try {
book?.updateInfo()
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(context, R.string.null_book, Toast.LENGTH_SHORT).show()
findNavController().popBackStack()
return@launch
}
Log.d("MyBF", "read path: ${book?.path}")
for (i in 1..4) {
mBookHandler?.sendEmptyMessageDelayed(i, (100*i).toLong())
}
book?.updateVolumes {
mBookHandler?.sendEmptyMessage(10)
}
}
} else {
@@ -83,7 +90,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
isOnPause = false
bookHandler.set(mBookHandler)
activity?.apply {
toolbar.title = mBookHandler?.book?.results?.comic?.name
toolbar.title = book?.name
}
setStartRead()
}
@@ -95,17 +102,15 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
override fun onDestroy() {
super.onDestroy()
mBookHandler?.destroy()
mBookHandler?.ads?.forEach {
it.exit = true
}
mBookHandler?.exit = true
book?.exit = true
bookHandler.set(null)
}
fun setStartRead() {
if(mBookHandler?.chapterNames?.isNotEmpty() == true) activity?.apply {
mBookHandler?.book?.results?.comic?.let { comic ->
getPreferences(MODE_PRIVATE).getInt(comic.name, -1).let { p ->
book?.name?.let { name ->
getPreferences(MODE_PRIVATE).getInt(name, -1).let { p ->
this@BookFragment.lbbstart.apply {
var i = 0
if(p >= 0) {
@@ -114,7 +119,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
setOnClickListener {
mBookHandler?.urlArray?.let {
Reader.viewMangaAt(comic.name, i, it)
Reader.viewMangaAt(name, i, it)
}
}
}
@@ -127,9 +132,9 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
fun setAddToShelf() {
if(mBookHandler?.chapterNames?.isNotEmpty() != true) return
lifecycleScope.launch {
MainActivity.shelf?.query(mBookHandler?.path!!)?.let { b ->
MainActivity.shelf?.query(book?.path!!)?.let { b ->
mBookHandler?.collect = b.results?.collect?:-2
Log.d("MyBF", "get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}")
Log.d("MyBF", "get collect of ${book?.path} = ${mBookHandler?.collect}")
tic.text = b.results?.browse?.chapter_name?.let { name ->
getString(R.string.text_format_cloud_read_to).format(name)
}
@@ -140,7 +145,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
}
}
mBookHandler?.book?.results?.comic?.let { comic ->
book?.uuid?.let { uuid ->
this@BookFragment.lbbsub.setOnClickListener {
lifecycleScope.launch clickLaunch@ {
if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) {
@@ -154,7 +159,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
return@clickLaunch
}
val re = MainActivity.shelf?.add(comic.uuid)
val re = MainActivity.shelf?.add(uuid)
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
if (re == "修改成功") {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
@@ -169,13 +174,10 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
val bundle = Bundle()
Log.d("MyBF", "nav2: ${arguments?.getString("path")?:"null"}")
bundle.putString("path", arguments?.getString("path")?:"null")
bundle.putString("name", mBookHandler!!.book?.results?.comic?.name)
if(mBookHandler!!.vols != null && mBookHandler!!.json != null) {
bundle.putString("loadJson", mBookHandler!!.json)
bundle.putString("name", book!!.name!!)
if(book?.volumes != null && book?.json != null) {
bundle.putString("loadJson", book!!.json)
}
bundle.putStringArray("group", mBookHandler!!.gpws)
bundle.putStringArray("groupNames", mBookHandler!!.keys)
bundle.putIntArray("count", mBookHandler!!.cnts)
findNavController().let {
Navigate.safeNavigateTo(it, R.id.action_nav_book_to_nav_group, bundle)
}

View File

@@ -1,15 +1,14 @@
package top.fumiama.copymanga.ui.book
import android.graphics.Bitmap
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.graphics.drawable.toBitmap
import androidx.core.widget.NestedScrollView
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
@@ -18,7 +17,6 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.tabs.TabLayoutMediator
import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.fragment_book.*
@@ -32,49 +30,26 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.BookInfoStructure
import top.fumiama.copymanga.json.ChapterStructure
import top.fumiama.copymanga.json.ThemeStructure
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.http.AutoDownloadHandler
import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideBlurTransformation
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
: AutoDownloadHandler(th.get()?.getString(R.string.bookInfoApiUrl)?.format(CMApi.myHostApiUrl, path)?: "",
BookInfoStructure::class.java,
th.get()){
class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.myLooper()!!) {
private val that get() = th.get()
private var hasToastedError = false
get(){
val re = field
field = true
return re
}
var book: BookInfoStructure? = null
private var complete = false
var ads = emptyArray<PausableDownloader>()
var gpws = arrayOf<String>()
var keys = arrayOf<String>()
var cnts = intArrayOf()
var vols: Array<VolumeStructure>? = null
var chapterNames = arrayOf<String>()
var collect: Int = -1
var json: String? = null
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.lbl, false)
var chapterNames = arrayOf<String>()
var collect: Int = -1
var urlArray = arrayOf<String>()
var exit = false
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
@@ -85,44 +60,10 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
3 -> setAuthorsAndTags()
6 -> if(complete) that?.navigate2dl()
9 -> endSetLayouts()
10 -> setVolumes()
}
}
override fun onError() {
super.onError()
if(exit) return
if(!hasToastedError) /*that?.activity?.runOnUiThread*/ {
Toast.makeText(that?.context, R.string.null_book, Toast.LENGTH_SHORT).show()
that?.apply { findNavController().popBackStack() }
}
}
override fun setGsonItem(gsonObj: Any): Boolean {
val pass = super.setGsonItem(gsonObj)
book = gsonObj as BookInfoStructure
return pass
}
override fun getGsonItem() = book
override suspend fun doWhenFinishDownload() = withContext(Dispatchers.IO) {
super.doWhenFinishDownload()
if(exit) return@withContext
if(keys.isEmpty()) book?.results?.groups?.values?.forEach {
keys += it.name
gpws += it.path_word
if (it.count == 0) {
it.count = 1
}
cnts += it.count
Log.d("MyBFH", "Add caption: ${it.name} @ ${it.path_word} of ${it.count}")
}
for (i in 1..4) {
sendEmptyMessageDelayed(i, (100*i).toLong())
}
if(vols?.isEmpty() != false) initComicData()
}
private fun endSetLayouts() {
if (exit) return
that?.fbloading?.apply {
@@ -138,50 +79,36 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
private fun setCover() {
if (exit) return
that?.apply {
book?.results?.comic?.cover?.let { cover ->
val load = Glide.with(this).load(
GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders)
).timeout(10000).addListener(GlideHideLottieViewListener(WeakReference(laic)))
load.into(imic)
context?.let { it1 -> GlideBlurTransformation(it1) }
?.let { it2 -> RequestOptions.bitmapTransform(it2) }
?.let { it3 -> load.apply(it3).into(lbibg) }
}
val load = Glide.with(this).load(
if (book?.cover != null)
GlideUrl(CMApi.proxy?.wrap(book?.cover!!)?:book?.cover!!, CMApi.myGlideHeaders)
else book?.cachedCover
).timeout(10000).addListener(GlideHideLottieViewListener(WeakReference(laic)))
load.into(imic)
context?.let { it1 -> GlideBlurTransformation(it1) }
?.let { it2 -> RequestOptions.bitmapTransform(it2) }
?.let { it3 -> load.apply(it3).into(lbibg) }
//imf?.visibility = View.GONE
//fbl?.addView(divider)
}
}
/*private fun getThemeSeq(authors: Array<ThemeStructure>): CharSequence{
var re = ""
for(author in authors) re += author.name + ' '
return re
}*/
private fun setTexts() {
if (exit) return
//that?.tic?.text = book?.name
//that?.tic?.visibility = View.GONE
mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name
that?.btauth?.text = that?.getString(R.string.text_format_region)?.format(
book?.results?.comic?.region?.display
)
that?.bttag?.text = that?.getString(R.string.text_format_img_type)?.format(when(book?.results?.comic?.img_type) {
1 -> "条漫"
2 -> "普通"
else -> "未知类型${book?.results?.comic?.img_type}"
})
that?.bthit?.text = that?.getString(R.string.text_format_hit)?.format(
book?.results?.comic?.popular
)
that?.btsub?.text = that?.getString(R.string.text_format_stat)?.format(
book?.results?.comic?.status?.display
)
that?.bttime?.text = book?.results?.comic?.datetime_updated
val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.lbl, false)
(v as TextView).text = book?.results?.comic?.brief
that?.lbl?.addView(v)
that?.lbl?.addView(divider)
that?.apply {
// tic?.text = book?.name
// tic?.visibility = View.GONE
mainWeakReference?.get()?.toolbar?.title = book?.name
btauth?.text = that?.getString(R.string.text_format_region)?.format(book?.region?:"未知")
bttag?.text = that?.getString(R.string.text_format_img_type)?.format(book?.imageType?:"未知")
bthit?.text = that?.getString(R.string.text_format_hit)?.format(book?.popular?:-1)
btsub?.text = that?.getString(R.string.text_format_stat)?.format(book?.status?:"未知")
bttime?.text = book?.updateTime?:"未知"
val v = layoutInflater.inflate(R.layout.line_text_info, lbl, false)
(v as TextView).text = book?.brief
lbl?.addView(v)
lbl?.addView(divider)
}
}
private fun setTheme(caption: String, themeStructure: Array<ThemeStructure>, nav: Int) {
@@ -230,7 +157,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
private fun setAuthorsAndTags() {
if (exit) return
that?.apply {
book?.results?.comic?.apply {
book?.apply {
author?.let {
setTheme(
getString(R.string.author),
@@ -257,21 +184,22 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
private suspend fun setVolume(fbl: LinearLayout, p: Int) = withContext(Dispatchers.IO) {
if (exit) return@withContext
that?.apply {
book?.results?.apply {
book?.apply {
var i = 0
for (j in 0 until p) {
i += vols?.get(j)?.results?.list?.size?:0
i += volumes[j].results?.list?.size?:0
}
var last = i-1
vols?.get(p)?.let { v ->
val comicName = name?:return@withContext
volumes[p].let { v ->
if(exit) return@withContext
var line: View? = null
last += v.results.list.size
v.results.list.forEach {
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[p], it.name)
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comicName, keys[p], it.name)
//Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}")
that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) sleep(100)
while (isOnPause && !exit) sleep(500)
if (exit) return@withContext
}?:return@withContext
if(line == null) {
@@ -282,7 +210,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
Log.d("MyBH", "add last single chapter ${it.name}")
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) }
}
line?.let { l -> addVolumesView(fbl, l) }
} else {
@@ -291,14 +219,14 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) }
}
}
} else line?.l2cr?.apply {
lct.text = it.name
if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success)
val index = i
setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }
setOnClickListener { Reader.viewMangaAt(comicName, index, urlArray) }
line?.let { l -> addVolumesView(fbl, l) }
line = null
}
@@ -312,26 +240,27 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
private suspend fun setViewManga() = withContext(Dispatchers.IO) {
if (exit) return@withContext
that?.apply {
book?.results?.apply {
book?.apply {
val comicName = name?:return@withContext
ViewMangaActivity.fileArray = arrayOf()
urlArray = arrayOf()
ViewMangaActivity.uuidArray = arrayOf()
var i = 0
var last = -1
vols?.forEachIndexed { groupIndex, v ->
volumes.forEachIndexed { groupIndex, v ->
if(exit) return@withContext
last += v.results.list.size
v.results.list.forEach {
urlArray += CMApi.getChapterInfoApiUrl(
comic.path_word,
path,
it.uuid
)?:""
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[groupIndex], it.name)
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comicName, keys[groupIndex], it.name)
ViewMangaActivity.fileArray += f
chapterNames += it.name
ViewMangaActivity.uuidArray += it.uuid
that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) sleep(100)
while (isOnPause && !exit) sleep(500)
if (exit) return@withContext
}?:return@withContext
i++
@@ -352,120 +281,20 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
}
}
private suspend fun initComicData() = withContext(Dispatchers.IO) withIO@ {
var volumes = emptyArray<VolumeStructure>()
val counts = cnts.clone()
gpws.forEachIndexed { i, gpw ->
Log.d("MyBFH", "下载:$gpw")
var offset = 0
val times = counts[i] / 100
val remain = counts[i] % 100
val re = arrayOfNulls<VolumeStructure>(if(remain != 0) (times+1) else (times))
if (re.isEmpty()) {
withContext(Dispatchers.Main) {
Toast.makeText(that?.context, "获取${gpw}失败", Toast.LENGTH_SHORT).show()
}
return@forEachIndexed
}
Log.d("MyBFH", "${i}卷共${if(times == 0) 1 else times}次加载")
do {
counts[i] = counts[i] - 100
CMApi.getGroupInfoApiUrl(path, gpw, offset)?.let {
Log.d("MyBFH", "get api: $it")
if(ComicDlFragment.exit) return@withIO
val ad = PausableDownloader(it) { result ->
try {
val r = Gson().fromJson(result.decodeToString(), VolumeStructure::class.java)
re[r.results.offset / 100] = r
Log.d("MyBFH", "${i}卷返回, 大小: ${r.results.list.size}")
} catch (e: Exception) {
e.printStackTrace()
that?.findNavController()?.popBackStack()
}
}
ads += ad
ad.run()
offset += 100
sleep(100)
}
} while (counts[i] > 0)
var c = 0
while (c++ < 80) {
sleep(100)
if(ComicDlFragment.exit) return@withIO
if(re.all { it != null }) break
}
if(re.isNotEmpty()) {
val r = re[0]
var s = emptyArray<ChapterStructure>()
re.forEach { v ->
v?.results?.list?.forEach {
s += it
}
}
r?.results?.list = s
r?.apply { volumes += this }
} else re[0]?.apply { volumes += this }
}
var c = 0
while (c < 80 && volumes.size != gpws.size) {
sleep(100)
if(ComicDlFragment.exit) return@withIO
Log.d("MyBFH", "已有:${volumes.size} 共:${gpws.size}")
c++
}
if (volumes.size == gpws.size) {
saveVolumes(volumes)
that?.fbtab?.let { tab ->
that?.fbvp?.let { vp ->
withContext(Dispatchers.Main) {
vp.adapter = ViewData(vp).RecyclerViewAdapter()
TabLayoutMediator(tab, vp) { t, p ->
t.text = keys[p]
}.attach()
}
private fun setVolumes() {
that?.apply {
fbtab?.let { tab ->
fbvp?.let { vp ->
vp.adapter = ViewData(vp).RecyclerViewAdapter()
TabLayoutMediator(tab, vp) { t, p ->
t.text = book?.keys?.get(p)
}.attach()
}
}
setViewManga()
lifecycleScope.launch { setViewManga() }
}
}
private suspend fun saveVolumes(volumes: Array<VolumeStructure>) = withContext(Dispatchers.IO) {
that?.context?.getExternalFilesDir("")?.let { home ->
book?.results?.comic?.name?.let { name ->
val mangaFolder = File(home, name)
if(!mangaFolder.exists()) mangaFolder.mkdirs()
json = Gson().toJson(volumes)
File(mangaFolder, "info.json").writeText(json!!)
File(mangaFolder, "grps.json").writeText(Gson().toJson(keys))
that?.apply {
var cnt = 0
var success = false
while (cnt++ < 10 && !success) {
sleep(100)
if (exit) return@withContext
File(mangaFolder, "head.jpg").let { head ->
val fo = head.outputStream()
try {
imic.drawable.toBitmap().compress(Bitmap.CompressFormat.JPEG, 90, fo)
success = true
} catch (e: Exception) {
e.printStackTrace()
}
fo.close()
}
}
if (!success) withContext(Dispatchers.Main) {
Toast.makeText(that?.context, R.string.download_cover_timeout, Toast.LENGTH_SHORT).show()
}
}
}
}
vols = volumes
}
inner class ViewData(itemView: View): RecyclerView.ViewHolder(itemView) {
inner class RecyclerViewAdapter: RecyclerView.Adapter<ViewData>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData {
@@ -476,7 +305,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
that?.lifecycleScope?.launch { setVolume(holder.itemView.fbl, position) }
}
override fun getItemCount(): Int = keys.size
override fun getItemCount(): Int = that?.book?.keys?.size?:0
}
}
}

View File

@@ -1,9 +1,13 @@
package top.fumiama.copymanga.ui.cardflow.rank
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_rank.*
import kotlinx.android.synthetic.main.line_rank.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.UITools
@@ -17,6 +21,7 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
private var sortValue = 0
private val audienceWay = listOf("", "male", "female")
private var audience = 0 // 0 all 1 male 2 female
private var isLoading = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -39,6 +44,11 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
ad?.exit = true
}
override fun onLoadFinish() {
super.onLoadFinish()
isLoading = false
}
override fun getApiUrl() =
getString(R.string.rankApiUrl).format(
CMApi.myHostApiUrl,
@@ -53,48 +63,45 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
override fun onTabReselected(tab: TabLayout.Tab?) {}
override fun onTabSelected(tab: TabLayout.Tab?) {
setSortValue(tab?.position?:0)
sortValue = tab?.position?:0
if(!isLoading) delayedRefresh()
}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
})
}
private fun setSortValue(value: Int) {
sortValue = value
Thread{
sleep(400)
if(ad?.exit != true) activity?.runOnUiThread {
reset()
addPage()
private fun delayedRefresh() {
lifecycleScope.launch {
isLoading = true
withContext(Dispatchers.IO) {
sleep(400)
withContext(Dispatchers.Main) {
reset()
addPage()
}
}
}.start()
}
}
fun showSexInfo(toolsBox: UITools) {
if (ad?.exit != false) return
toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型",
"男频", "全部", "女频", {
audience = 1
reset()
Thread {
sleep(600)
addPage()
}.start()
if(!isLoading) {
audience = 1
delayedRefresh()
}
}, {
audience = 0
reset()
Thread {
sleep(600)
addPage()
}.start()
if(!isLoading) {
audience = 0
delayedRefresh()
}
}, {
audience = 2
reset()
Thread {
sleep(600)
addPage()
}.start()
if(!isLoading) {
audience = 2
delayedRefresh()
}
})
}

View File

@@ -45,7 +45,9 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
PausableDownloader(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) {
if(ad?.exit == true) return@PausableDownloader
it.let {
filter = Gson().fromJson(it.inputStream().reader(), FilterStructure::class.java)
it.inputStream().use { i ->
filter = Gson().fromJson(i.reader(), FilterStructure::class.java)
}
if(ad?.exit == true) return@PausableDownloader
withContext(Dispatchers.Main) {
if(ad?.exit != true) setClasses()

View File

@@ -26,18 +26,16 @@ class TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_to
PausableDownloader(getString(R.string.topicApiUrl).format(CMApi.myHostApiUrl, arguments?.getString("path"))) { data ->
withContext(Dispatchers.IO) {
if(ad?.exit == true) return@withContext
data.apply {
val r = inputStream().reader()
data.inputStream().use { i ->
val r = i.reader()
Gson().fromJson(r, TopicStructure::class.java)?.apply {
if(ad?.exit == true) return@withContext
activity?.let {
withContext(Dispatchers.Main) withMain@ {
if(ad?.exit == true) return@withMain
it.toolbar.title = results.title
ftttime.text = results.datetime_created
fttintro.text = results.intro
type = results.type
}
withContext(Dispatchers.Main) withMain@ {
if(ad?.exit == true) return@withMain
activity?.toolbar?.title = results.title
ftttime.text = results.datetime_created
fttintro.text = results.intro
type = results.type
}
}
}

View File

@@ -4,7 +4,6 @@ import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
@@ -12,11 +11,8 @@ import kotlinx.android.synthetic.main.fragment_dlcomic.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.ChapterStructure
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.template.general.NoBackRefreshFragment
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
@@ -24,7 +20,6 @@ import java.lang.ref.WeakReference
class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
var ltbtn: View? = null
private var ads = emptyArray<PausableDownloader>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exit = false
@@ -43,11 +38,7 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
)
}
}
else -> initComicData(
arguments?.getString("path"),
arguments?.getStringArray("group"),
arguments?.getIntArray("count")
)
else -> findNavController().popBackStack()
}
}
}
@@ -59,9 +50,6 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
handler?.downloading = false
handler?.mangaDlTools?.exit = true
handler?.dl?.dismiss()
ads.forEach {
it.exit = true
}
exit = true
handler = null
}
@@ -91,73 +79,6 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
private fun loadFromJson(json: String) = Gson().fromJson(json, Array<VolumeStructure>::class.java)
private fun loadGroupsFromFile(file: File) = Gson().fromJson(file.reader(), Array<String>::class.java)
/*private fun setMenuInvisible(menu: Menu){
menu.findItem(R.id.action_download)?.isVisible = false
}*/
private suspend fun initComicData(pw: String?, gpws: Array<String>?, counts: IntArray?) = withContext(Dispatchers.IO) {
var volumes = emptyArray<VolumeStructure>()
if (gpws != null) {
gpws.forEachIndexed { i, gpw ->
Log.d("MyCDF", "下载:$gpw")
var offset = 0
val times = (counts?.get(i)?:1) / 100
val remain = (counts?.get(i)?:1) % 100
val re = arrayOfNulls<VolumeStructure>(if(remain != 0) (times+1) else (times))
Log.d("MyCDF", "${i}卷共${if(times == 0) 1 else times}次加载")
do {
counts?.set(i, counts[i] - 100)
CMApi.getGroupInfoApiUrl(pw, gpw, offset)?.let {
if(exit) return@withContext
val ad = PausableDownloader(it) { result ->
Log.d("MyCDF", "${i}卷返回")
val r = Gson().fromJson(result.decodeToString(), VolumeStructure::class.java)
re[r.results.offset / 100] = r
}
ads += ad
try {
ad.run()
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(context, "加载${gpw}${i}部分失败", Toast.LENGTH_SHORT).show()
findNavController().popBackStack()
}
}
offset += 100
}
} while ((counts?.get(i) ?: 0) > 0)
var c = 0
while (c++ < 80) {
sleep(1000)
if(exit) return@withContext
if(re.all { it != null }) break
}
if(re.size > 1) {
val r = re[0]
var s = emptyArray<ChapterStructure>()
re.forEach {
it?.results?.list?.forEach {
s += it
}
}
r?.results?.list = s
r?.apply { volumes += this }
} else re[0]?.apply { volumes += this }
}
var c = 0
while (c < 80 && volumes.size != gpws.size) {
sleep(1000)
if(exit) return@withContext
Log.d("MyCDF", "已有:${volumes.size} 共:${gpws.size}")
c++
}
if (volumes.size == gpws.size) {
start2load(volumes)
}
}
}
private suspend fun initOldComicData() = withContext(Dispatchers.IO) {
handler = ComicDlHandler(Looper.myLooper()!!, WeakReference(this@ComicDlFragment),
arguments?.getString("name")?:"null")

View File

@@ -122,7 +122,7 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_download)
return@setOnClickListener
}
callDownloadFragment(name)
callBookFragment(name)
}
v.setOnLongClickListener {
if (name == oldDlCardName && path == oldDlCardName) {
@@ -132,7 +132,7 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground)
.setTitle(R.string.new_download_card_option_hint)
.setItems(arrayOf("删除数据", "前往详情")) { d, p ->
.setItems(arrayOf("删除数据文件夹", "直接前往下载页")) { d, p ->
d.cancel()
when (p) {
0 -> {
@@ -150,12 +150,7 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
}.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
1 -> {
val bundle = Bundle()
bundle.putBoolean("loadJson", true)
bundle.putString("name", name)
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_book, bundle)
}
1 -> callDownloadFragment(name)
}
}
.show()
@@ -166,7 +161,14 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
}
}
private fun callDownloadFragment(name: String){
private fun callBookFragment(name: String) {
val bundle = Bundle()
bundle.putBoolean("loadJson", true)
bundle.putString("name", name)
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_book, bundle)
}
private fun callDownloadFragment(name: String) {
val bundle = Bundle()
Log.d("MyNDF", "Call dl and is new.")
bundle.putString("loadJson", File(File(extDir, name), "info.json").readText())

View File

@@ -14,6 +14,7 @@ import kotlinx.android.synthetic.main.widget_infodrawer.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.Chapter2Return
import top.fumiama.copymanga.json.ChapterWithContent
import top.fumiama.copymanga.json.ComicStructure
@@ -191,8 +192,8 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
}
}
private suspend fun fakeLoad() {
PausableDownloader(chapterUrl) { _ -> }.run()
private suspend fun fakeLoad() = withContext(Dispatchers.IO) {
if(MainActivity.member?.hasLogin == true) PausableDownloader(chapterUrl) { _ -> }.run()
}
private suspend fun prepareManga() = withContext(Dispatchers.Main) {

View File

@@ -301,7 +301,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
private fun canCut(inputStream: InputStream): Boolean{
val op = BitmapFactory.Options()
op.inJustDecodeBounds = true
BitmapFactory.decodeStream(inputStream, null, op)
inputStream.use {
BitmapFactory.decodeStream(it, null, op)
}
Log.d("MyVM", "w: ${op.outWidth}, h: ${op.outHeight}")
return op.outWidth.toFloat() / op.outHeight.toFloat() > 1
}
@@ -437,13 +439,18 @@ class ViewMangaActivity : TitleActivityTemplate() {
loadImg(imgView, it, useCut, isLeft, false)
}
else {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
val sleepTime = loadImgOnWait.getAndIncrement().toLong()*200
Log.d("MyVM", "loadImgOn sleep: $sleepTime ms")
val re = tasks?.get(index2load)
if (sleepTime > 0 && re?.isDone != true) Thread.sleep(sleepTime)
if (sleepTime > 0 && re?.isDone != true) {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
Thread.sleep(sleepTime)
}
if (re != null) {
if(!re.isDone) re.run()
if(!re.isDone) {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
re.run()
}
val data = re.get()
if(data != null && data.isNotEmpty()) {
BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
@@ -451,9 +458,15 @@ class ViewMangaActivity : TitleActivityTemplate() {
Log.d("MyVM", "Load position $position from task")
}?:Log.d("MyVM", "null bitmap at $position")
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
else getImgUrl(index2load)?.let {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
loadImgUrlInto(imgView, it, useCut, isLeft)
}
}
else getImgUrl(index2load)?.let {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
loadImgUrlInto(imgView, it, useCut, isLeft)
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
loadImgOnWait.decrementAndGet()
tasks?.apply {
if (index2load >= size) return@apply
@@ -484,7 +497,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
}
}
imgView.visibility = View.VISIBLE
withContext(Dispatchers.Main) {
if(imgView.visibility != View.VISIBLE) imgView.visibility = View.VISIBLE
}
}
private fun loadOneImg() {
@@ -515,11 +530,16 @@ class ViewMangaActivity : TitleActivityTemplate() {
for (i in 0..1) {
val ext = if((i == 0 && tryWebpFirst) || (i == 1 && !tryWebpFirst)) "webp" else "jpg"
bitmap = try {
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.$ext")))
else {
val out = ByteArrayOutputStream()
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.$ext")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
zip.getInputStream(zip.getEntry("${position}.$ext"))?.use { zipInputStream ->
if (q == 100) BitmapFactory.decodeStream(zipInputStream)
else {
ByteArrayOutputStream().use { out ->
BitmapFactory.decodeStream(zipInputStream)?.compress(Bitmap.CompressFormat.JPEG, q, out)
ByteArrayInputStream(out.toByteArray()).use { i ->
BitmapFactory.decodeStream(i)
}
}
}
}
} catch (e: Exception) {
if (i == 1) {

View File

@@ -73,7 +73,7 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
} catch (e: Exception) {
val l = LoginInfoStructure()
l.code = 450
l.message = "${getString(R.string.login_get_avatar_failed)}: ${e.localizedMessage}"
l.message = "${getString(R.string.login_get_avatar_failed)}: $e"
l
}
}