1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-27 14:20:30 +08:00
新增
1. 双页切分显示预载进度
2. 阅览漫画标题栏显示漫画名
修复
1. 一次下载过多漫画可能导致的闪退
优化
1. 阅览漫画定位逻辑
2. VM参数传递, 调用方式
3. 登录错误提示
This commit is contained in:
源文雨
2024-03-16 23:44:11 +09:00
parent f0e7802eb2
commit aa0190fbb7
17 changed files with 315 additions and 2727 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
<changelist name="Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]" date="1709911381682" recycled="true" deleted="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch" />
<option name="DESCRIPTION" value="Uncommitted changes before Update at 2024/3/9, 12:23 AM [Changes]" />
</changelist>

View File

@@ -8,8 +8,8 @@ android {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 53 versionCode 54
versionName '2.2.5' versionName '2.2.6'
resourceConfigurations += ['zh', 'zh-rCN'] resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -24,13 +24,13 @@ class MangaDlTools {
PausableDownloader(url.toString(), 1000) { data -> PausableDownloader(url.toString(), 1000) { data ->
try { try {
Gson().fromJson(data.decodeToString(), Chapter2Return::class.java)?.let { Gson().fromJson(data.decodeToString(), Chapter2Return::class.java)?.let {
getChapterInfo(it, index, chapterName, group) downloadChapter(it, index, chapterName, group)
} }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error") onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error")
} }
}.run() }.run().let { if (!it) onDownloadedListener?.handleMessage(index, false, "获取章节信息错误") }
} }
@Synchronized private fun prepareDownloadListener() { @Synchronized private fun prepareDownloadListener() {
@@ -57,8 +57,8 @@ class MangaDlTools {
indexMap[f] = index indexMap[f] = index
} }
private fun getChapterInfo(chapter2Return: Chapter2Return, index: Int, chapterName: CharSequence, group: CharSequence) { private fun downloadChapter(chapter2Return: Chapter2Return, index: Int, chapterName: CharSequence, group: CharSequence) {
if(index >= 0){ if(index >= 0) {
val f = "$chapterName.zip" val f = "$chapterName.zip"
setPool(chapter2Return.results.comic.name, group) setPool(chapter2Return.results.comic.name, group)
setIndexMap(f, index) setIndexMap(f, index)

View File

@@ -5,38 +5,61 @@ import android.content.Intent
import android.util.Log import android.util.Log
import androidx.core.content.edit import androidx.core.content.edit
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.button_tbutton.view.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.ui.vm.ViewMangaActivity import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import java.io.File import java.io.File
object Reader { object Reader {
fun start2viewManga(name: String, pos: Int, urlArray: Array<String>, fromFirstPage: Boolean = false) { var fileArray = arrayOf<File>()
fun start2viewManga(name: String?, pos: Int, urlArray: Array<String>, uuidArray: 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 {
putInt(name, pos)
apply()
Log.d("MyR", "记录 $name 阅读到第 ${pos+1}")
}?: Log.d("MyR", "无法获得 main pref")
// ViewMangaActivity.dlhandler = null // ViewMangaActivity.dlhandler = null
ViewMangaActivity.position = pos
ViewMangaActivity.comicName = name
val zipf = ViewMangaActivity.fileArray[pos]
val intent = Intent(this, ViewMangaActivity::class.java) val intent = Intent(this, ViewMangaActivity::class.java)
name?.let { n ->
getPreferences(Context.MODE_PRIVATE)?.edit {
putInt(n, pos)
apply()
Log.d("MyR", "记录 $n 阅读到第 ${pos+1}")
}?: Log.d("MyR", "无法获得 main pref")
intent.putExtra("comicName", name)
}
intent.putExtra("position", pos)
intent.putExtra("urlArray", urlArray) intent.putExtra("urlArray", urlArray)
if(!fromFirstPage) { intent.putExtra("uuidArray", uuidArray)
if (!fromFirstPage) {
intent.putExtra("function", "log") intent.putExtra("function", "log")
ViewMangaActivity.pn = -2 intent.putExtra("pn", -2)
} }
if (zipf.exists()) { val zipFile = fileArray[pos]
ViewMangaActivity.zipFile = zipf if (zipFile.exists()) {
intent.putExtra("zipFile", zipFile.absolutePath)
//intent.putExtra("callFrom", "zipFirst") //intent.putExtra("callFrom", "zipFirst")
startActivity(intent)
} else {
ViewMangaActivity.zipFile = null
startActivity(intent)
} }
startActivity(intent)
}
}
fun viewOldMangaZipFile(fileArray: Array<File>, name: String, pos: Int, zipFile: File) {
Reader.fileArray = fileArray
mainWeakReference?.get()?.apply {
val intent = Intent(this, ViewMangaActivity::class.java)
intent.putExtra("comicName", name)
intent.putExtra("position", pos)
intent.putExtra("zipFile", zipFile.absolutePath)
startActivity(intent)
}
}
fun viewMangaZipFile(pos: Int, urlArray: Array<String>, uuidArray: Array<String>, zipFile: File) {
mainWeakReference?.get()?.apply {
val intent = Intent(this, ViewMangaActivity::class.java)
intent.putExtra("position", pos)
.putExtra("urlArray", urlArray)
.putExtra("uuidArray", uuidArray)
.putExtra("callFrom", "zipFirst")
.putExtra("zipFile", zipFile.absolutePath)
startActivity(intent)
} }
} }
fun getComicPathWordInFolder(file: File): String { fun getComicPathWordInFolder(file: File): String {

View File

@@ -8,12 +8,11 @@ import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
import kotlin.random.Random import kotlin.random.Random
class PausableDownloader(private val url: String, private val waitMilliseconds: Long = 0, private val isApi: Boolean = true, private val whenFinish: (suspend (result: ByteArray)->Unit)? = null) { class PausableDownloader(private val url: String, private val waitMilliseconds: Long = 0, private val isApi: Boolean = true, private val whenFinish: (suspend (result: ByteArray)->Unit)? = null) {
var exit = false var exit = false
suspend fun run() = withContext(Dispatchers.IO) { suspend fun run(): Boolean = withContext(Dispatchers.IO) {
var c = 0 var c = 0
while (!exit && c++ < 3) { while (!exit && c++ < 3) {
try { try {
@@ -23,12 +22,13 @@ class PausableDownloader(private val url: String, private val waitMilliseconds:
mainWeakReference?.get()?.getString(R.string.pc_ua)!! mainWeakReference?.get()?.getString(R.string.pc_ua)!!
)) ))
whenFinish?.let { it(data) } whenFinish?.let { it(data) }
break return@withContext true
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
if (waitMilliseconds > 0) delay(200+Random.nextLong(waitMilliseconds)) if (waitMilliseconds > 0) delay(200+Random.nextLong(waitMilliseconds))
} }
} }
Log.d("MyPD", "found exit = $exit") Log.d("MyPD", "found exit = $exit")
return@withContext false
} }
} }

View File

@@ -1,6 +1,9 @@
package top.fumiama.copymanga.tools.http package top.fumiama.copymanga.tools.http
import android.util.Log import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -14,7 +17,7 @@ import java.util.zip.ZipOutputStream
import kotlin.random.Random import kotlin.random.Random
class DownloadPool(folder: String) { class DownloadPool(folder: String) {
class Quest(val fileName: String, val imgUrl: Array<String>, val refer: String? = null) class Quest(val fileName: String, val imgUrl: Array<String>)
var exit = false var exit = false
set(value) { set(value) {
if(value) { if(value) {
@@ -33,8 +36,9 @@ class DownloadPool(folder: String) {
if(!saveFolder.exists()) saveFolder.mkdirs() if(!saveFolder.exists()) saveFolder.mkdirs()
} }
operator fun plusAssign(quest: Quest) { operator fun plusAssign(quest: Quest): Unit {
packZipFile(quest.fileName, quest.imgUrl) packZipFile(quest.fileName, quest.imgUrl)
Log.d("MyDP", "+= ${quest.fileName}, size: ${quest.imgUrl.size}")
} }
fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) { fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) {
@@ -46,83 +50,81 @@ class DownloadPool(folder: String) {
} }
private fun packZipFile(fileName: String, imgUrls: Array<String>) { private fun packZipFile(fileName: String, imgUrls: Array<String>) {
Thread { File(saveFolder, "$fileName.tmp").let { f ->
File(saveFolder, "$fileName.tmp").let { f -> f.parentFile?.let { if(!it.exists()) it.mkdirs() }
f.parentFile?.let { if(!it.exists()) it.mkdirs() } var start = 0
var start = 0 Log.d("MyDP", "Zip file: ${f.absolutePath}")
Log.d("MyDP", "Zip file: ${f.absolutePath}") if(f.exists()) {
if(f.exists()) { try {
try { val zipFile = ZipFile(f)
val zipFile = ZipFile(f) start = zipFile.size()
start = zipFile.size() zipFile.close()
zipFile.close() Log.d("MyDP", "next download index: $start")
Log.d("MyDP", "next download index: $start") if (start <= 0 || start >= imgUrls.size) { // error or re-download
if (start <= 0 || start >= imgUrls.size) { // error or re-download
f.delete()
f.createNewFile()
start = 0
}
} catch (e: Exception) {
e.printStackTrace()
f.delete() f.delete()
f.createNewFile() f.createNewFile()
start = 0
} }
} else f.createNewFile()
val zip: ZipOutputStream
if (start > 0) {
val fromZip = ZipInputStream(f.readBytes().inputStream())
zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f), CRC32()))
zip.setLevel(9)
fromZip.use { z ->
var e = z.nextEntry
while (e != null) {
zip.putNextEntry(e)
z.copyTo(zip)
zip.closeEntry()
z.closeEntry()
e = z.nextEntry
}
}
} else {
zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f), CRC32()))
zip.setLevel(9)
}
var succeed = true
var lastIndex = -8
try {
for(index in start until imgUrls.size) {
while (wait && !exit) sleep(100+Random.nextLong(1000))
if(exit) break
var tryTimes = 3
var s = false
while (!s && tryTimes-- > 0) {
val u = imgUrls[index]
s = (DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(u)?:u), -1))?.let {
zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}"))
zip.write(it)
zip.closeEntry()
true
}?:false
if(exit) break
if (!s) sleep(2000)
if(exit) break
}
if(!s && tryTimes <= 0) {
succeed = false
mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false, "超过最大重试次数") }
break
} else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true, "") }
lastIndex = index
}
zip.close()
if (succeed && lastIndex+1 >= imgUrls.size) f.renameTo(File(saveFolder, fileName))
mOnPageDownloadListener?.let { it(fileName, 0, 0, true, "") }
mOnDownloadListener?.let { it(fileName, succeed, "") }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
mOnDownloadListener?.let { it(fileName, false, e.localizedMessage?:"packZipFile") } f.delete()
f.createNewFile()
} }
} else f.createNewFile()
val zip: ZipOutputStream
if (start > 0) {
val fromZip = ZipInputStream(f.readBytes().inputStream())
zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f), CRC32()))
zip.setLevel(9)
fromZip.use { z ->
var e = z.nextEntry
while (e != null) {
zip.putNextEntry(e)
z.copyTo(zip)
zip.closeEntry()
z.closeEntry()
e = z.nextEntry
}
}
} else {
zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f), CRC32()))
zip.setLevel(9)
} }
}.start() var succeed = true
var lastIndex = -8
try {
for(index in start until imgUrls.size) {
while (wait && !exit) sleep(100+Random.nextLong(1000))
if(exit) break
var tryTimes = 3
var s = false
while (!s && tryTimes-- > 0) {
val u = imgUrls[index]
s = (DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(u)?:u), -1))?.let {
zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}"))
zip.write(it)
zip.closeEntry()
true
}?:false
if(exit) break
if (!s) sleep(2000)
if(exit) break
}
if(!s && tryTimes <= 0) {
succeed = false
mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false, "超过最大重试次数") }
break
} else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true, "") }
lastIndex = index
}
zip.close()
if (succeed && lastIndex+1 >= imgUrls.size) f.renameTo(File(saveFolder, fileName))
mOnPageDownloadListener?.let { it(fileName, 0, 0, true, "") }
mOnDownloadListener?.let { it(fileName, succeed, "") }
} catch (e: Exception) {
e.printStackTrace()
mOnDownloadListener?.let { it(fileName, false, e.localizedMessage?:"packZipFile") }
}
}
} }
} }

View File

@@ -115,15 +115,14 @@ object DownloadTools {
fun prepare(url: String?): FutureTask<ByteArray?>? = fun prepare(url: String?): FutureTask<ByteArray?>? =
url?.let { url?.let {
Log.d("Mydl", "prepareHttp: $it") Log.d("Mydl", "prepareHttp: $it")
var ret: ByteArray? = null
val task = FutureTask(Callable { val task = FutureTask(Callable {
var ret: ByteArray? = null
try { try {
val connection = getNormalConnection(it, "GET") val connection = getNormalConnection(it, "GET")
connection.inputStream?.use { ci ->
val ci = connection?.inputStream ret = ci.readBytes()
ret = ci?.readBytes() }
ci?.close() connection.disconnect()
connection?.disconnect()
} catch (ex: Exception) { } catch (ex: Exception) {
ex.printStackTrace() ex.printStackTrace()
} }

View File

@@ -105,8 +105,8 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
i = p i = p
} }
setOnClickListener { setOnClickListener {
mBookHandler?.urlArray?.let { mBookHandler?.apply {
Reader.start2viewManga(name, i, it) Reader.start2viewManga(name, i, urlArray, uuidArray)
} }
} }
} }

View File

@@ -49,6 +49,7 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
var chapterNames = arrayOf<String>() var chapterNames = arrayOf<String>()
var collect: Int = -1 var collect: Int = -1
var urlArray = arrayOf<String>() var urlArray = arrayOf<String>()
var uuidArray = arrayOf<String>()
var exit = false var exit = false
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
@@ -210,7 +211,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.start2viewManga(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) }
} }
line?.let { l -> addVolumesView(fbl, l) } line?.let { l -> addVolumesView(fbl, l) }
} else { } else {
@@ -219,14 +220,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.start2viewManga(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) }
} }
} }
} 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.start2viewManga(comicName, index, urlArray) } setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) }
line?.let { l -> addVolumesView(fbl, l) } line?.let { l -> addVolumesView(fbl, l) }
line = null line = null
} }
@@ -242,9 +243,9 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
that?.apply { that?.apply {
book?.apply { book?.apply {
val comicName = name?:return@withContext val comicName = name?:return@withContext
ViewMangaActivity.fileArray = arrayOf() Reader.fileArray = arrayOf()
urlArray = arrayOf() urlArray = arrayOf()
ViewMangaActivity.uuidArray = arrayOf() uuidArray = arrayOf()
var i = 0 var i = 0
var last = -1 var last = -1
volumes.forEachIndexed { groupIndex, v -> volumes.forEachIndexed { groupIndex, v ->
@@ -256,9 +257,9 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
it.uuid it.uuid
)?:"" )?:""
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comicName, keys[groupIndex], it.name) val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comicName, keys[groupIndex], it.name)
ViewMangaActivity.fileArray += f Reader.fileArray += f
chapterNames += it.name chapterNames += it.name
ViewMangaActivity.uuidArray += it.uuid uuidArray += it.uuid
that?.isOnPause?.let { isOnPause -> that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) delay(500) while (isOnPause && !exit) delay(500)
if (exit) return@withContext if (exit) return@withContext

View File

@@ -3,7 +3,6 @@ package top.fumiama.copymanga.ui.comicdl
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Dialog import android.app.Dialog
import android.content.Intent
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.Message import android.os.Message
@@ -13,29 +12,31 @@ import android.view.ViewTreeObserver
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.fragment_book.*
import kotlinx.android.synthetic.main.line_chapter.view.*
import kotlinx.android.synthetic.main.widget_downloadbar.*
import kotlinx.android.synthetic.main.fragment_dlcomic.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
import kotlinx.android.synthetic.main.button_tbutton.* import kotlinx.android.synthetic.main.button_tbutton.*
import kotlinx.android.synthetic.main.button_tbutton.view.* import kotlinx.android.synthetic.main.button_tbutton.view.*
import kotlinx.android.synthetic.main.fragment_book.*
import kotlinx.android.synthetic.main.fragment_dlcomic.*
import kotlinx.android.synthetic.main.line_caption.view.* import kotlinx.android.synthetic.main.line_caption.view.*
import kotlinx.android.synthetic.main.line_chapter.view.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
import kotlinx.android.synthetic.main.widget_downloadbar.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.ChapterStructure import top.fumiama.copymanga.json.ChapterStructure
import top.fumiama.copymanga.json.ComicStructureOld import top.fumiama.copymanga.json.ComicStructureOld
import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.manga.MangaDlTools import top.fumiama.copymanga.manga.MangaDlTools
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.exit
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json
import top.fumiama.copymanga.ui.vm.ViewMangaActivity import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import top.fumiama.copymanga.views.ChapterToggleButton import top.fumiama.copymanga.views.ChapterToggleButton
import top.fumiama.copymanga.views.LazyScrollView import top.fumiama.copymanga.views.LazyScrollView
import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -62,6 +63,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
private var finishMap = arrayOf<Boolean?>() private var finishMap = arrayOf<Boolean?>()
var downloading = false var downloading = false
private var urlArray = arrayOf<String>() private var urlArray = arrayOf<String>()
private var uuidArray = arrayOf<String>()
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
@@ -111,8 +113,8 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
if(isOld) analyzeOldStructure() if(isOld) analyzeOldStructure()
else { else {
urlArray = arrayOf() urlArray = arrayOf()
ViewMangaActivity.fileArray = arrayOf() Reader.fileArray = arrayOf()
ViewMangaActivity.uuidArray = arrayOf() uuidArray = arrayOf()
vols.forEachIndexed { i, vol -> vols.forEachIndexed { i, vol ->
val caption = groupNames?.get(i)?:vol.results.list[0].group_path_word val caption = groupNames?.get(i)?:vol.results.list[0].group_path_word
Log.d("MyCDH", "caption: $caption, group name: ${groupNames?.get(i)}") Log.d("MyCDH", "caption: $caption, group name: ${groupNames?.get(i)}")
@@ -269,16 +271,14 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
i.isEnabled = false i.isEnabled = false
} }
i.url?.let { i.url?.let {
Thread { launch {
that?.lifecycleScope?.launch { mangaDlTools.downloadChapterInVol(
mangaDlTools.downloadChapterInVol( it,
it, i.chapterName,
i.chapterName, i.caption?:"null",
i.caption?:"null", i.index
i.index )
) }
}
}.start()
} }
} }
} }
@@ -308,6 +308,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
} }
private suspend fun onZipDownloadFailure(index: Int, message: String) = withContext(Dispatchers.Main) { private suspend fun onZipDownloadFailure(index: Int, message: String) = withContext(Dispatchers.Main) {
if (exit) return@withContext
tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error) tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error)
tbtnlist[index].isEnabled = true tbtnlist[index].isEnabled = true
Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败: $message", Toast.LENGTH_SHORT).show() Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败: $message", Toast.LENGTH_SHORT).show()
@@ -345,7 +346,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
tbtncnt++ tbtncnt++
tbv.tbtn.uuid = uuid tbv.tbtn.uuid = uuid
ViewMangaActivity.uuidArray += uuid uuidArray += uuid
tbv.tbtn.chapterName = title tbv.tbtn.chapterName = title
tbv.tbtn.url = url tbv.tbtn.url = url
//tbv.tbtn.hint = caption //tbv.tbtn.hint = caption
@@ -358,7 +359,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val zipf = CMApi.getZipFile(that!!.context?.getExternalFilesDir(""), comicName, caption, title) val zipf = CMApi.getZipFile(that!!.context?.getExternalFilesDir(""), comicName, caption, title)
Log.d("MyCD", "Get zipf: $zipf") Log.d("MyCD", "Get zipf: $zipf")
ViewMangaActivity.fileArray += zipf Reader.fileArray += zipf
if (zipf.exists()) withContext(Dispatchers.Main) { if (zipf.exists()) withContext(Dispatchers.Main) {
tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked) tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
tbv.tbtn.isChecked = false tbv.tbtn.isChecked = false
@@ -367,13 +368,9 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
if (zipf.exists() && !multiSelect) { if (zipf.exists() && !multiSelect) {
it.tbtn.setBackgroundResource(R.drawable.rndbg_checked) it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
it.tbtn.isChecked = false it.tbtn.isChecked = false
ViewMangaActivity.zipFile = zipf
ViewMangaActivity.dlHandler = this@ComicDlHandler ViewMangaActivity.dlHandler = this@ComicDlHandler
ViewMangaActivity.position = it.tbtn.index
dl?.show() dl?.show()
val intent = Intent(that?.context, ViewMangaActivity::class.java) Reader.viewMangaZipFile(it.tbtn.index, urlArray, uuidArray, zipf)
intent.putExtra("urlArray", urlArray).putExtra("callFrom", "zipFirst")
that?.startActivity(intent)
} else { } else {
it.tbtn.setBackgroundResource(R.drawable.toggle_button) it.tbtn.setBackgroundResource(R.drawable.toggle_button)
if (it.tbtn.isChecked) that?.tdwn?.text = "$dldChapter/${++checkedChapter}" if (it.tbtn.isChecked) that?.tdwn?.text = "$dldChapter/${++checkedChapter}"
@@ -393,14 +390,9 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
} else { } else {
toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定", toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定",
null, "取消", { null, "取消", {
ViewMangaActivity.zipFile = null
ViewMangaActivity.dlHandler = this@ComicDlHandler ViewMangaActivity.dlHandler = this@ComicDlHandler
ViewMangaActivity.position = it.tbtn.index
dl?.show() dl?.show()
Reader.start2viewManga(null, it.tbtn.index, urlArray, uuidArray)
val intent = Intent(that?.context, ViewMangaActivity::class.java)
intent.putExtra("urlArray", urlArray)
that?.startActivity(intent)
}, null, null }, null, null
) )
} }

View File

@@ -1,7 +1,6 @@
package top.fumiama.copymanga.ui.download package top.fumiama.copymanga.ui.download
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
@@ -15,10 +14,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.general.NoBackRefreshFragment import top.fumiama.copymanga.template.general.NoBackRefreshFragment
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.ui.vm.ViewMangaActivity
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
import java.util.regex.Pattern import java.util.regex.Pattern
@@ -64,12 +63,10 @@ class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) {
} }
chosenFile.name.endsWith(".zip") -> { chosenFile.name.endsWith(".zip") -> {
Toast.makeText(context, "加载中...", Toast.LENGTH_SHORT).show() Toast.makeText(context, "加载中...", Toast.LENGTH_SHORT).show()
ViewMangaActivity.zipFile = chosenFile Reader.viewOldMangaZipFile(
ViewMangaActivity.comicName = it[position] it.map { File(cd, it) }.toTypedArray(),
ViewMangaActivity.position = position it[position], position, chosenFile
ViewMangaActivity.fileArray = it.map { File(cd, it) }.toTypedArray() )
// ViewMangaActivity.urlArray = Array(it.size) {return@Array ""}
startActivity(Intent(context, ViewMangaActivity::class.java))
} }
} }
} }

View File

@@ -2,8 +2,6 @@ package top.fumiama.copymanga.ui.vm
import android.widget.Toast import android.widget.Toast
import top.fumiama.copymanga.manga.Reader import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -38,7 +36,7 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
} }
return return
} }
val chapterPosition = position + if(goNext) 1 else -1 val chapterPosition = v.position + if(goNext) 1 else -1
if (v.urlArray.isEmpty()) return if (v.urlArray.isEmpty()) return
if(chapterPosition < 0 || chapterPosition >= v.urlArray.size) { if(chapterPosition < 0 || chapterPosition >= v.urlArray.size) {
Toast.makeText(v.applicationContext, R.string.end_of_chapter, Toast.LENGTH_SHORT).show() Toast.makeText(v.applicationContext, R.string.end_of_chapter, Toast.LENGTH_SHORT).show()
@@ -48,7 +46,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.start2viewManga(it, chapterPosition, v.urlArray, goNext) } v.comicName?.let { Reader.start2viewManga(it, chapterPosition, v.urlArray, v.uuidArray, goNext) }
v.finish() v.finish()
return return
} }

View File

@@ -9,10 +9,12 @@ import android.view.View
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_viewmanga.* import kotlinx.android.synthetic.main.activity_viewmanga.*
import kotlinx.android.synthetic.main.dialog_unzipping.*
import kotlinx.android.synthetic.main.widget_infodrawer.* import kotlinx.android.synthetic.main.widget_infodrawer.*
import kotlinx.android.synthetic.main.widget_infodrawer.view.* import kotlinx.android.synthetic.main.widget_infodrawer.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.Chapter2Return import top.fumiama.copymanga.json.Chapter2Return
@@ -20,10 +22,6 @@ import top.fumiama.copymanga.json.ChapterWithContent
import top.fumiama.copymanga.json.ComicStructure import top.fumiama.copymanga.json.ComicStructure
import top.fumiama.copymanga.template.http.AutoDownloadHandler import top.fumiama.copymanga.template.http.AutoDownloadHandler
import top.fumiama.copymanga.template.http.PausableDownloader import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.pn
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.uuidArray
import top.fumiama.copymanga.views.ScaleImageView import top.fumiama.copymanga.views.ScaleImageView
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
@@ -97,11 +95,11 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
LOAD_IMAGES_INTO_LINE -> wv.get()?.lifecycleScope?.launch { loadImagesIntoLine() } LOAD_IMAGES_INTO_LINE -> wv.get()?.lifecycleScope?.launch { loadImagesIntoLine() }
RESTORE_PAGE_NUMBER -> { RESTORE_PAGE_NUMBER -> {
sendEmptyMessage(DIALOG_HIDE) sendEmptyMessage(DIALOG_HIDE)
wv.get()?.restorePN() wv.get()?.apply { lifecycleScope.launch { restorePN() } }
} }
LOAD_PAGE_FROM_ITEM -> { LOAD_PAGE_FROM_ITEM -> {
val verticalMaxCount = wv.get()?.verticalLoadMaxCount?:20 val verticalMaxCount = wv.get()?.verticalLoadMaxCount?:20
val item = (pn - 1) / verticalMaxCount * verticalMaxCount val item = ((wv.get()?.pn?:1) - 1) / verticalMaxCount * verticalMaxCount
loadScrollMode(item) loadScrollMode(item)
Log.d("MyVMH", "Load page from $item") Log.d("MyVMH", "Load page from $item")
} }
@@ -130,6 +128,7 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
} }
DO_LAMBDA -> (msg.obj as? Runnable?)?.run() DO_LAMBDA -> (msg.obj as? Runnable?)?.run()
SET_NET_INFO -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netInfo SET_NET_INFO -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netInfo
SET_DL_TEXT -> dl.tunz.text = msg.obj as String
} }
} }
override fun getGsonItem() = manga override fun getGsonItem() = manga
@@ -159,9 +158,9 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
prepareManga() prepareManga()
} }
suspend fun loadFromFile(file: File): Boolean = withContext(Dispatchers.IO) { suspend fun loadFromFile(file: File): Boolean {
fakeLoad() fakeLoad()
return@withContext try { return try {
val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json") val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json")
if(jsonFile.exists()) { if(jsonFile.exists()) {
manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java) manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java)
@@ -172,13 +171,15 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
manga?.let { manga?.let {
it.results = Chapter2Return.Results() it.results = Chapter2Return.Results()
it.results.comic = ComicStructure() it.results.comic = ComicStructure()
it.results.comic.name = file.parentFile?.name it.results.comic.name = file.parentFile?.parentFile?.name
it.results.chapter = ChapterWithContent() it.results.chapter = ChapterWithContent()
it.results.chapter.name = file.nameWithoutExtension it.results.chapter.name = file.nameWithoutExtension
it.results.chapter.uuid = uuidArray[position] wv.get()?.apply {
wv.get()?.countZipEntries { c -> it.results.chapter.uuid = uuidArray[position]
it.results.chapter.size = c countZipEntries { c ->
prepareManga() it.results.chapter.size = c
prepareManga()
}
} }
} }
} }
@@ -190,19 +191,21 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
} }
} }
private suspend fun fakeLoad() = withContext(Dispatchers.IO) { private fun fakeLoad() {
if(MainActivity.member?.hasLogin == true) launch { if (MainActivity.member?.hasLogin == true) Thread {
PausableDownloader(chapterUrl) { _ -> }.run() runBlocking { PausableDownloader(chapterUrl) { _ -> }.run() }
} }.start()
} }
private suspend fun prepareManga() = withContext(Dispatchers.Main) { private suspend fun prepareManga() = withContext(Dispatchers.Main) {
if(comicName == null) { wv.get()?.apply {
comicName = manga?.results?.comic?.name if(comicName == null) {
comicName = manga?.results?.comic?.name
}
count = manga?.results?.chapter?.size?:0
initManga()
vprog?.visibility = View.GONE
} }
wv.get()?.count = manga?.results?.chapter?.size?:0
wv.get()?.initManga()
wv.get()?.vprog?.visibility = View.GONE
} }
private suspend fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = withContext(Dispatchers.IO) { private suspend fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = withContext(Dispatchers.IO) {
val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20) val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)
@@ -220,7 +223,7 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget() if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget()
obtainMessage(DO_LAMBDA, Runnable{ obtainMessage(DO_LAMBDA, Runnable{
doAfter?.run() doAfter?.run()
wv.get()?.updateSeekBar(0) wv.get()?.apply { lifecycleScope.launch { updateSeekBar(0) } }
}).sendToTarget() }).sendToTarget()
} }
} }
@@ -283,5 +286,6 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
const val DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO = 20 const val DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO = 20
const val DO_LAMBDA = 21 const val DO_LAMBDA = 21
const val SET_NET_INFO = 22 const val SET_NET_INFO = 22
const val SET_DL_TEXT = 23
} }
} }

View File

@@ -12,10 +12,14 @@ import android.graphics.drawable.Drawable
import android.media.AudioManager import android.media.AudioManager
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper
import android.util.Log import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.* import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
@@ -115,6 +119,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
val realCount get() = if(cut) indexMap.size else count val realCount get() = if(cut) indexMap.size else count
var urlArray = arrayOf<String>() var urlArray = arrayOf<String>()
var uuidArray = arrayOf<String>()
var position = 0
var comicName: String? = null
private var zipFile: File? = null
var pn = 0
private val loadImgOnWait = AtomicInteger() private val loadImgOnWait = AtomicInteger()
@@ -149,6 +158,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
//dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true" //dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
//zipFirst = intent.getStringExtra("callFrom") == "zipFirst" //zipFirst = intent.getStringExtra("callFrom") == "zipFirst"
intent.getStringArrayExtra("urlArray")?.let { urlArray = it } intent.getStringArrayExtra("urlArray")?.let { urlArray = it }
intent.getStringArrayExtra("uuidArray")?.let { uuidArray = it }
position = intent.getIntExtra("position", 0)
comicName = intent.getStringExtra("comicName")
zipFile = intent.getStringExtra("zipFile")?.let { File(it) }
pn = intent.getIntExtra("pn", 0)
cut = pb["useCut"] cut = pb["useCut"]
r2l = pb["r2l"] r2l = pb["r2l"]
verticalLoadMaxCount = settingsPref?.getInt("settings_cat_vm_sb_vertical_max", 20)?.let { if(it > 0) it else 20 }?:20 verticalLoadMaxCount = settingsPref?.getInt("settings_cat_vm_sb_vertical_max", 20)?.let { if(it > 0) it else 20 }?:20
@@ -221,7 +235,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
) )
} }
fun restorePN() { suspend fun restorePN() = withContext(Dispatchers.Main) {
if (isPnValid) { if (isPnValid) {
isInScroll = false isInScroll = false
pageNum = pn pageNum = pn
@@ -242,41 +256,51 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
@ExperimentalStdlibApi @ExperimentalStdlibApi
private fun doPrepareWebImg() = Thread { private suspend fun doPrepareWebImg() = withContext(Dispatchers.IO) {
getImgUrlArray()?.apply { getImgUrlArray()?.apply {
if(cut) { if(cut) {
Log.d("MyVM", "is cut, load all pages...") Log.d("MyVM", "is cut, load all pages...")
handler.sendEmptyMessage(VMHandler.DIALOG_SHOW) //showDl handler.sendEmptyMessage(VMHandler.DIALOG_SHOW) // showDl
isCut = BooleanArray(size) isCut = BooleanArray(size)
val analyzedCnt = BooleanArray(size)
forEachIndexed { i, it -> forEachIndexed { i, it ->
if(it != null) { handler.obtainMessage(VMHandler.SET_DL_TEXT, "$i/$size").sendToTarget()
Thread{ if(it != null) try {
DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let { DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let {
isCut[i] = canCut(it) isCut[i] = canCut(it)
analyzedCnt[i] = true }?:run {
withContext(Dispatchers.Main) {
Toast.makeText(this@ViewMangaActivity, R.string.touch_img_error, Toast.LENGTH_SHORT)
.show()
finish()
} }
}.start() return@withContext
Thread.sleep(22) }
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(this@ViewMangaActivity, R.string.analyze_img_size_error, Toast.LENGTH_SHORT)
.show()
finish()
}
return@withContext
} }
} }
while (analyzedCnt.count { it } != size) Thread.sleep(233)
isCut.forEachIndexed { index, b -> isCut.forEachIndexed { index, b ->
Log.d("MyVM", "[$index] cut: $b") Log.d("MyVM", "[$index] cut: $b")
indexMap += index+1 indexMap += index+1
if(b) indexMap += -(index+1) if(b) indexMap += -(index+1)
} }
handler.sendEmptyMessage(15) //hideDl handler.sendEmptyMessage(15) // hideDl
Log.d("MyVM", "load all pages finished") Log.d("MyVM", "load all pages finished")
} }
count = size count = size
runOnUiThread { prepareItems() } prepareItems()
if (notUseVP) prepareDownloadTasks() if (notUseVP) prepareDownloadTasks()
} }
}.start() }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
fun initManga() { suspend fun initManga() = withContext(Dispatchers.IO) {
val uuid = handler.manga?.results?.chapter?.uuid val uuid = handler.manga?.results?.chapter?.uuid
Log.d("MyVM", "initManga, chapter uuid: $uuid") Log.d("MyVM", "initManga, chapter uuid: $uuid")
if (uuid != null && uuid != "") { if (uuid != null && uuid != "") {
@@ -333,14 +357,13 @@ class ViewMangaActivity : TitleActivityTemplate() {
Log.d("MyVM", "setPageNumber($num)") Log.d("MyVM", "setPageNumber($num)")
if (r2l && !notUseVP) vp.currentItem = realCount - num if (r2l && !notUseVP) vp.currentItem = realCount - num
else if (notUseVP) { else if (notUseVP) {
if(isVertical){ if(isVertical) {
currentItem = num - 1 currentItem = num - 1
val offset = currentItem % verticalLoadMaxCount val offset = currentItem % verticalLoadMaxCount
Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}") Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}")
if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size
updateSeekBar() lifecycleScope.launch { updateSeekBar() }
} } else {
else {
currentItem = num - 1 currentItem = num - 1
try { try {
loadOneImg() loadOneImg()
@@ -353,23 +376,24 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
} else { } else {
Log.d("MyVM", "Set vp current: ${num-1}") Log.d("MyVM", "Set vp current: ${num-1}")
var delta = num - 1 - vp.currentItem //var delta = num - 1 - vp.currentItem
if(delta >= 1) Thread{ vp.currentItem = num - 1
while (delta-- > 0){ /*lifecycleScope.launch {
Thread.sleep(23) withContext(Dispatchers.IO) {
runOnUiThread { if(delta >= 1) while (delta-- > 0){
vp.currentItem++ delay(20)
withContext(Dispatchers.Main) {
vp.currentItem++
}
}
else if(delta <= -1) while (delta++ < 0){
delay(20)
withContext(Dispatchers.Main) {
vp.currentItem--
}
} }
} }
}.start() }*/
else if(delta <= -1) Thread{
while (delta++ < 0){
Thread.sleep(23)
runOnUiThread {
vp.currentItem--
}
}
}.start()
} }
} }
@@ -565,7 +589,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
@ExperimentalStdlibApi @ExperimentalStdlibApi
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
private fun prepareItems() { private suspend fun prepareItems(): Unit = withContext(Dispatchers.Main) {
try { try {
prepareVP() prepareVP()
prepareInfoBar() prepareInfoBar()
@@ -588,7 +612,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
} }
private fun setProgress() { private suspend fun setProgress() = withContext(Dispatchers.IO) {
handler.manga?.results?.chapter?.uuid?.let { handler.manga?.results?.chapter?.uuid?.let {
getPreferences(MODE_PRIVATE).edit { getPreferences(MODE_PRIVATE).edit {
//it["chapterId"] = hm.chapterId.toString() //it["chapterId"] = hm.chapterId.toString()
@@ -653,18 +677,18 @@ class ViewMangaActivity : TitleActivityTemplate() {
vp.adapter = ViewData(vp).RecyclerViewAdapter() vp.adapter = ViewData(vp).RecyclerViewAdapter()
vp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { vp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
updateSeekBar()
super.onPageSelected(position) super.onPageSelected(position)
lifecycleScope.launch { updateSeekBar() }
} }
}) })
if (r2l && !isPnValid) vp.currentItem = realCount - 1 if (r2l && !isPnValid) vp.currentItem = realCount - 1
} }
} }
fun updateSeekBar(p: Int = 0) { suspend fun updateSeekBar(p: Int = 0) = withContext(Dispatchers.Main) {
if (p > 0) { if (p > 0) {
updateSeekText(p) updateSeekText(p)
return return@withContext
} }
if (!isInSeek) hideDrawer() if (!isInSeek) hideDrawer()
updateSeekText() updateSeekText()
@@ -677,7 +701,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
oneinfo.alpha = 0F oneinfo.alpha = 0F
infseek.visibility = View.GONE infseek.visibility = View.GONE
isearch.visibility = View.GONE isearch.visibility = View.GONE
inftitle.ttitle.text = handler.manga?.results?.chapter?.name inftitle.ttitle.text = "$comicName ${handler.manga?.results?.chapter?.name}"
inftxtprogress.text = "$pageNum/$realCount" inftxtprogress.text = "$pageNum/$realCount"
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
var p = 0 var p = 0
@@ -726,7 +750,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
} else isInSeek = false } else isInSeek = false
} }
private fun after() { private fun after() {
if(manualCount++ < 3) p = pageNum else updateSeekBar(p) if(manualCount++ < 3) p = pageNum else lifecycleScope.launch { updateSeekBar(p) }
} }
}) })
isearch.setImageResource(R.drawable.ic_author) isearch.setImageResource(R.drawable.ic_author)
@@ -786,7 +810,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) { if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) {
Log.d("MyVM", "Do scroll back, isVertical: $isVertical, pageNum: $pageNum") Log.d("MyVM", "Do scroll back, isVertical: $isVertical, pageNum: $pageNum")
if (isInSeek) { if (isInSeek) {
updateSeekBar(pageNum-1) (pageNum-1).let { lifecycleScope.launch { updateSeekBar(it) } }
return return
} }
handler.obtainMessage( handler.obtainMessage(
@@ -805,7 +829,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
pageNum++ pageNum++
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) { if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) {
if (isInSeek) { if (isInSeek) {
updateSeekBar(pageNum+1) (pageNum+1).let { lifecycleScope.launch { updateSeekBar(it) } }
return return
} }
handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE) handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE)
@@ -917,14 +941,8 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
companion object { companion object {
var comicName: String? = null
var uuidArray = arrayOf<String>()
var fileArray = arrayOf<File>()
var position = 0
var zipFile: File? = null
var dlHandler: Handler? = null var dlHandler: Handler? = null
var va: WeakReference<ViewMangaActivity>? = null var va: WeakReference<ViewMangaActivity>? = null
var pn = 0
var noCellarAlert = false var noCellarAlert = false
} }
} }

View File

@@ -3,7 +3,6 @@ package top.fumiama.copymanga.user
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Base64 import android.util.Base64
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.stream.JsonReader
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.LoginInfoStructure import top.fumiama.copymanga.json.LoginInfoStructure
@@ -16,35 +15,38 @@ import java.nio.charset.Charset
class Member(private val pref: SharedPreferences, private val getString: (Int) -> String) { class Member(private val pref: SharedPreferences, private val getString: (Int) -> String) {
val hasLogin: Boolean get() = pref.getString("token", "")?.isNotEmpty()?:false val hasLogin: Boolean get() = pref.getString("token", "")?.isNotEmpty()?:false
suspend fun login(username: String, pwd: String, salt: Int): LoginInfoStructure = withContext(Dispatchers.IO) { suspend fun login(username: String, pwd: String, salt: Int): LoginInfoStructure = withContext(Dispatchers.IO) {
try { var err = ""
getLoginConnection(username, pwd, salt).apply { getLoginConnection(username, pwd, salt).apply {
Gson().fromJson<LoginInfoStructure>( inputStream.use {
JsonReader(inputStream.reader()), LoginInfoStructure::class.java it?.readBytes()?.let { data ->
)?.let { data -> data.inputStream().use { dataIn ->
disconnect() try {
if(data.code == 200) { Gson().fromJson<LoginInfoStructure>(
pref.edit()?.apply { dataIn.reader(), LoginInfoStructure::class.java
putString("token", data.results?.token) )?.let { info ->
putString("user_id", data.results?.user_id) if(info.code == 200) {
putString("username", data.results?.username) pref.edit()?.apply {
putString("nickname", data.results?.nickname) putString("token", info.results?.token)
apply() putString("user_id", info.results?.user_id)
return@withContext info() putString("username", info.results?.username)
putString("nickname", info.results?.nickname)
apply()
return@withContext info()
}
}
return@withContext info
}?: run { err = getString(R.string.login_parse_json_error) }
} catch (e: Exception) {
err = data.decodeToString()
} }
} }
return@withContext data }?: run { err = getString(R.string.login_get_conn_failed) }
}
} }
val l = LoginInfoStructure()
l.code = 400
l.message = getString(R.string.login_get_conn_failed)
return@withContext l
} catch (e: Exception) {
val l = LoginInfoStructure()
l.code = 400
l.message = e.toString()
return@withContext l
} }
val l = LoginInfoStructure()
l.code = 400
l.message = err
return@withContext l
} }
@@ -61,18 +63,25 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
l.message = getString(R.string.noLogin) l.message = getString(R.string.noLogin)
return@withContext l return@withContext l
} }
return@withContext try { try {
val l = Gson().fromJson(DownloadTools.getHttpContent( val data = DownloadTools.getHttpContent(
getString(R.string.memberInfoApiUrl).format(CMApi.myHostApiUrl).let { getString(R.string.memberInfoApiUrl).format(CMApi.myHostApiUrl).let {
CMApi.apiProxy?.wrap(it)?:it CMApi.apiProxy?.wrap(it)?:it
} }
).decodeToString(), ).decodeToString()
LoginInfoStructure::class.java) try {
if(l.code == 200) pref.edit()?.apply { val l = Gson().fromJson(data, LoginInfoStructure::class.java)
putString("avatar", l.results.avatar) if(l.code == 200) pref.edit()?.apply {
apply() putString("avatar", l.results.avatar)
apply()
}
l
} catch (e : Exception) {
val l = LoginInfoStructure()
l.code = 450
l.message = "${getString(R.string.login_get_avatar_failed)}: $data"
l
} }
l
} catch (e: Exception) { } catch (e: Exception) {
val l = LoginInfoStructure() val l = LoginInfoStructure()
l.code = 450 l.code = 450

View File

@@ -56,6 +56,8 @@
<string name="load_page_number_error">第%1$d页加载异常</string> <string name="load_page_number_error">第%1$d页加载异常</string>
<string name="load_chapter_error">加载章节错误</string> <string name="load_chapter_error">加载章节错误</string>
<string name="show_image_error_try_lower_resolution">图片加载错误,请尝试下载后使用较低图片质量查看</string> <string name="show_image_error_try_lower_resolution">图片加载错误,请尝试下载后使用较低图片质量查看</string>
<string name="touch_img_error">预载图片头失败</string>
<string name="analyze_img_size_error">读取图片大小失败</string>
<string name="mainPageApiUrl">https://%1$s/api/v3/h5/homeIndex?platform=3</string> <string name="mainPageApiUrl">https://%1$s/api/v3/h5/homeIndex?platform=3</string>
<string name="referUrl">https://%1$s</string> <string name="referUrl">https://%1$s</string>
@@ -171,7 +173,8 @@
<string name="login_null_username">用户名为空</string> <string name="login_null_username">用户名为空</string>
<string name="login_null_pwd">密码为空</string> <string name="login_null_pwd">密码为空</string>
<string name="login_get_conn_failed">登录失败</string> <string name="login_get_conn_failed">登录失败</string>
<string name="login_get_avatar_failed">恢复登录失败</string> <string name="login_parse_json_error">解析返回数据失败</string>
<string name="login_get_avatar_failed">获取用户信息失败</string>
<string name="login_restart_to_apply">重启应用以彻底退出登录</string> <string name="login_restart_to_apply">重启应用以彻底退出登录</string>
<string name="old_download_card_name">前往旧版下载</string> <string name="old_download_card_name">前往旧版下载</string>