diff --git a/app/build.gradle b/app/build.gradle index 55939b4..110361b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId 'top.fumiama.copymanga' minSdkVersion 23 targetSdkVersion 31 - versionCode 22 - versionName '2.0.beta10' + versionCode 23 + versionName '2.0.beta11' resConfigs "zh", "zh-rCN" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt b/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt new file mode 100644 index 0000000..a24b40c --- /dev/null +++ b/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt @@ -0,0 +1,79 @@ +package top.fumiama.copymanga.manga + +import android.util.Log +import com.google.gson.Gson +import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference +import top.fumiama.copymanga.json.Chapter2Return +import top.fumiama.copymanga.template.http.AutoDownloadThread +import top.fumiama.copymanga.tools.http.DownloadPool +import java.io.File + +class MangaDlTools { + private var pool: DownloadPool? = null + private var grp: CharSequence = "" + private var indexMap = hashMapOf() + var exit: Boolean + get() = pool?.exit?:false + set(value) { pool?.exit = value } + var wait + get() = pool?.wait + set(value) { if (value != null) { pool?.wait = value } } + + fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int){ + Log.d("MyMDT", "下载:$url, index:$index") + AutoDownloadThread(url.toString()){ + Gson().fromJson(it?.decodeToString(), Chapter2Return::class.java)?.let { + if(it.results.chapter.words.size != it.results.chapter.size) downloadChapterInVol(url, chapterName, group, index) + else getChapterInfo(it, index, chapterName, group) + } + }.start() + } + + @Synchronized private fun setPool(comicName: String, group: CharSequence) { + if(pool == null || grp != group) { + pool = DownloadPool(File( + mainWeakReference?.get()?.getExternalFilesDir(""), + "$comicName/$group" + ).absolutePath) + grp = group + } + } + + @Synchronized private fun setIndexMap(f : String, index: Int) { + indexMap[f] = index + } + + private fun getChapterInfo(chapter2Return: Chapter2Return, index: Int, chapterName: CharSequence, group: CharSequence) { + if(index >= 0){ + val f = "$chapterName.zip" + setPool(chapter2Return.results.comic.name, group) + setIndexMap(f, index) + pool?.plusAssign(DownloadPool.Quest(f, getMangaUrls(chapter2Return))) + pool?.setOnDownloadListener { fileName: String, isSuccess: Boolean -> + indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, isSuccess) } + } + pool?.setOnPageDownloadListener { fileName: String, downloaded: Int, total: Int, isSuccess: Boolean -> + indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, downloaded, total, isSuccess) } + } + } + } + + private fun getMangaUrls(chapter2Return: Chapter2Return): Array{ + var re: Array = arrayOf() + val hm: HashMap = hashMapOf() + val chapter = chapter2Return.results.chapter + for(i in 0 until chapter.size) { + hm[chapter.words[i]] = chapter.contents[i].url + } + for(i in 0 until chapter.size){ + re += hm[i]?:"" + } + return re + } + + var onDownloadedListener: OnDownloadedListener? = null + interface OnDownloadedListener{ + fun handleMessage(index: Int, isSuccess: Boolean) + fun handleMessage(index: Int, downloaded: Int, total: Int, isSuccess: Boolean) + } +} diff --git a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt index 2697d85..78d2ed3 100644 --- a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt @@ -7,6 +7,7 @@ import android.util.Log import com.google.gson.Gson import top.fumiama.dmzj.copymanga.R import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference +import top.fumiama.copymanga.json.Chapter2Return import top.fumiama.copymanga.json.ReturnBase import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.thread.TimeThread @@ -22,7 +23,7 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C 0 -> setLayouts() } } - open fun setGsonItem(gsonObj: Any) {} + open fun setGsonItem(gsonObj: Any): Boolean = true open fun getGsonItem(): ReturnBase? = null open fun onError() {} open fun doWhenFinishDownload() {} @@ -33,22 +34,26 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C exit = true } private fun download(){ - Thread{ - DownloadTools.getHttpContent(url, - mainWeakReference?.get()?.getString(R.string.referUrl)!!, - mainWeakReference?.get()?.getString(R.string.pc_ua)!! - )?.let { - if(exit) return@Thread - val fi = it.inputStream() - setGsonItem(Gson().fromJson(fi.reader(), jsonClass)) - fi.close() - } - }.start() + Thread{ dlThread() }.start() checkTimes = 0 timeThread = TimeThread(this, callCheckMsg) timeThread?.canDo = true timeThread?.start() } + private fun dlThread() { + DownloadTools.getHttpContent(url, + mainWeakReference?.get()?.getString(R.string.referUrl)!!, + mainWeakReference?.get()?.getString(R.string.pc_ua)!! + )?.let { + if(exit) return + val fi = it.inputStream() + val pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass)) + fi.close() + if(!pass) { + dlThread() + } + } + } private fun check(){ val g = getGsonItem() if(g != null) { diff --git a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt new file mode 100644 index 0000000..1644368 --- /dev/null +++ b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt @@ -0,0 +1,85 @@ +package top.fumiama.copymanga.tools.http + +import android.util.Log +import java.io.File +import java.lang.Thread.sleep +import java.util.zip.CRC32 +import java.util.zip.CheckedOutputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + +class DownloadPool(folder: String) { + class Quest(val fileName: String, val imgUrl: Array, val refer: String? = null) + var exit = false + set(value) { + if(value) { + mOnDownloadListener = null + mOnPageDownloadListener = null + } + field = value + } + var wait = false + private val saveFolder = File(folder) + //fileName: String, isSuccess: Boolean + private var mOnDownloadListener: ((String, Boolean) -> Unit)? = null + //fileName: String, downloaded: Int, total: Int, isSuccess: Boolean + private var mOnPageDownloadListener: ((String, Int, Int, Boolean) -> Unit)? = null + init { + if(!saveFolder.exists()) saveFolder.mkdirs() + } + + operator fun plusAssign(quest: Quest) { + packZipFile(quest.fileName, quest.imgUrl, quest.refer?:"") + } + + operator fun plusAssign(quests: Array) { + Thread{ + quests.forEach { quest -> + packZipFile(quest.fileName, quest.imgUrl, quest.refer?:"") + sleep(1000) + } + }.start() + } + + fun setOnDownloadListener(onDownloadListener: (String, Boolean) -> Unit) { + mOnDownloadListener = onDownloadListener + } + + fun setOnPageDownloadListener(onPageDownloadListener: (String, Int, Int, Boolean) -> Unit) { + mOnPageDownloadListener = onPageDownloadListener + } + + private fun packZipFile(fileName: String, imgUrls: Array, refer: String) { + Thread{ + File(saveFolder, fileName).let { f -> + f.parentFile?.let { if(!it.exists()) it.mkdirs() } + if(f.exists()) f.delete() + f.createNewFile() + Log.d("MyDP", "Zip file: ${f.absolutePath}") + val zip = ZipOutputStream(CheckedOutputStream(f.outputStream(), CRC32())) + zip.setLevel(9) + var succeed = true + for(index in imgUrls.indices) { + while (wait && !exit) sleep(1000) + if(exit) break + zip.putNextEntry(ZipEntry("$index.jpg")) + var tryTimes = 3 + var s = false + while (!s && tryTimes-- > 0){ + s = (DownloadTools.getHttpContent(imgUrls[index], -1, refer)) ?.let { zip.write(it); true }?:false + if (!s) sleep(2000) + } + 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) } + //zip.flush() + } + zip.close() + mOnPageDownloadListener?.let { it(fileName, 0, 0, true) } + mOnDownloadListener?.let { it(fileName, succeed) } + } + }.start() + } +} \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt index 607bbc3..6ea8636 100644 --- a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt +++ b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt @@ -3,8 +3,10 @@ package top.fumiama.copymanga.tools.http import android.util.Log import top.fumiama.copymanga.tools.ssl.AllTrustManager import top.fumiama.copymanga.tools.ssl.IgnoreHostNameVerifier +import java.io.File import java.net.HttpURLConnection import java.net.URL +import java.net.URLEncoder import java.security.SecureRandom import java.util.concurrent.Callable import java.util.concurrent.FutureTask @@ -87,7 +89,7 @@ object DownloadTools { } } - fun getHttpContent(Url: String, readSize: Int? = null, refer: String? = "https://api.copymanga.com"): ByteArray? { + fun getHttpContent(Url: String, readSize: Int, refer: String? = "https://api.copymanga.com"): ByteArray? { Log.d("Mydl", "getHttp: $Url") var ret: ByteArray? = null val task = FutureTask(Callable { @@ -96,7 +98,7 @@ object DownloadTools { refer?.let { connection?.setRequestProperty("referer", it) } val ci = connection?.inputStream - if(readSize != null) { + if(readSize > 0) { ret = ByteArray(readSize) ci?.read(ret, 0, readSize) } else ret = ci?.readBytes() @@ -116,7 +118,7 @@ object DownloadTools { } } - fun touch(url: String?, refer: String? = "https://www.dmzj1.com"): FutureTask? = + fun touch(url: String?, refer: String? = "https://api.copymanga.com"): FutureTask? = url?.let { Log.d("Mydl", "touchHttp: $it") var ret: ByteArray? = null @@ -137,4 +139,40 @@ object DownloadTools { Thread(task).start() task } + + private fun replaceChineseCharacters(string: String?) : String? { + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.M) return string + else return string?.replace(Regex("(?<=/)[\\w\\s\\d\\u4e00-\\u9fa5.-]+(?=/?)")) { match -> + return@replace URLEncoder.encode(match.value, "UTF-8") + } + } + + fun downloadUsingUrlRet(url: String?, f: File, refer: String?): Boolean { + Log.d("Mydl", "Ret Get url: $url, File: $f") + val task = FutureTask(Callable { + val connection = getConnection(replaceChineseCharacters(url)) + if(refer != null) connection?.setRequestProperty("referer", refer) + + if (f.exists()) f.delete() + else f.parentFile?.mkdirs() + f.parentFile?.let { + if (!it.canRead()) it.setReadable(true) + if (!it.canWrite()) it.setWritable(true) + } + val ci = connection?.inputStream + val fo = f.outputStream() + ci?.buffered()?.copyTo(fo) + fo.close() + ci?.close() + connection?.disconnect() + return@Callable true + }) + Thread(task).start() + return try { + task.get() + } catch (ex: Exception) { + ex.printStackTrace() + false + } + } } \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/tools/http/MangaDlTools.kt b/app/src/main/java/top/fumiama/copymanga/tools/http/MangaDlTools.kt deleted file mode 100644 index 6d82d20..0000000 --- a/app/src/main/java/top/fumiama/copymanga/tools/http/MangaDlTools.kt +++ /dev/null @@ -1,108 +0,0 @@ -package top.fumiama.copymanga.tools.http - -import android.util.Log -import com.google.gson.Gson -import top.fumiama.dmzj.copymanga.R -import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference -import top.fumiama.copymanga.json.Chapter2Return -import top.fumiama.copymanga.template.http.AutoDownloadThread -import top.fumiama.copymanga.tools.http.DownloadTools.getHttpContent -import java.io.File -import java.lang.Thread.sleep -import java.util.zip.CRC32 -import java.util.zip.CheckedOutputStream -import java.util.zip.ZipEntry -import java.util.zip.ZipOutputStream - -class MangaDlTools { - var exit = false - private var comicFileRelative: String? = null - var size = 0 - var complete = false - var wait = false - - fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int){ - comicFileRelative = "$group/$chapterName.zip" - complete = false - getChapterInfo(url, index) - while (!complete) sleep(1000) - } - - private fun getChapterInfo(chapter2Return: Chapter2Return, index: Int) { - if(index >= 0){ - comicFileRelative?.let { - dlChapterAndPackIntoZip( - File( - mainWeakReference?.get()?.getExternalFilesDir(""), - "${chapter2Return.results.comic.name}/$it" - ), - getMangaUrls(chapter2Return) - ) - } - } - } - - private fun getMangaUrls(chapter2Return: Chapter2Return): Array{ - var re: Array = arrayOf() - val hm: HashMap = hashMapOf() - val chapter = chapter2Return.results.chapter - for(i in 0 until chapter.size) { - hm[chapter.words[i]] = chapter.contents[i].url - } - for(i in 0 until chapter.size){ - re += hm[i]?:"" - } - size = re.size - return re - } - - private fun getChapterInfo(url: CharSequence, index: Int){ - Log.d("MyMDT", "下载:$url, index:$index") - AutoDownloadThread(url.toString()){ - Gson().fromJson(it?.decodeToString(), Chapter2Return::class.java)?.let { - getChapterInfo(it, index) - } - }.start() - } - - private fun dlChapterAndPackIntoZip(zipf: File, urls: Array) { - zipf.parentFile?.let { if (!it.exists()) it.mkdirs() } - if (zipf.exists()) zipf.delete() - zipf.createNewFile() - val zip = ZipOutputStream(CheckedOutputStream(zipf.outputStream(), CRC32())) - zip.setLevel(9) - var succeed = true - for (i in urls.indices) { - while (wait && !exit) sleep(1000) - if (exit) break - zip.putNextEntry(ZipEntry("$i.webp")) - var tryTimes = 3 - var s = false - while (!s && tryTimes-- > 0) { - s = getHttpContent( - urls[i], - mainWeakReference?.get()?.getString(R.string.referUrl), - mainWeakReference?.get()?.getString(R.string.pc_ua) - )?.let { zip.write(it); true } ?: false - if (!s) { - onDownloadedListener?.handleMessage(i + 1) - sleep(2000) - } - } - if (!s && tryTimes <= 0) succeed = false - onDownloadedListener?.handleMessage(s, i + 1) - zip.flush() - } - zip.close() - onDownloadedListener?.handleMessage(succeed) - complete = true - } - - var onDownloadedListener: OnDownloadedListener? = null - - interface OnDownloadedListener { - fun handleMessage(succeed: Boolean) - fun handleMessage(succeed: Boolean, pageNow: Int) - fun handleMessage(pageNow: Int) - } -} diff --git a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt index b523c0a..a08123e 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt @@ -27,7 +27,6 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { bookHandler.startLoad() }.start() } - else bookHandler.fbibinfo?.layoutParams?.height = (bookHandler.fbibinfo?.width?:0 * 4.0 / 9.0 + 0.5).toInt() } override fun onResume() { @@ -37,6 +36,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { toolbar.title = bookHandler.book?.results?.comic?.name } setStartRead() + bookHandler.fbibinfo?.layoutParams?.height = ((bookHandler.fbibinfo?.width?:0) * 4.0 / 9.0 + 0.5).toInt() } override fun onDestroy() { diff --git a/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt index edc0540..4ec307a 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt @@ -91,9 +91,10 @@ class BookHandler(that: WeakReference, private val path: String) } } - override fun setGsonItem(gsonObj: Any) { - super.setGsonItem(gsonObj) + override fun setGsonItem(gsonObj: Any): Boolean { + val pass = super.setGsonItem(gsonObj) book = gsonObj as BookInfoStructure + return pass } override fun getGsonItem() = book diff --git a/app/src/main/java/top/fumiama/copymanga/ui/chapter/ChapterHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/chapter/ChapterHandler.kt index 87e0025..b4d2ee2 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/chapter/ChapterHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/chapter/ChapterHandler.kt @@ -39,9 +39,10 @@ class ChapterHandler(that: WeakReference, pw: String, gpw: Stri } override fun getGsonItem() = chapters - override fun setGsonItem(gsonObj: Any) { - super.setGsonItem(gsonObj) + override fun setGsonItem(gsonObj: Any) :Boolean { + val pass = super.setGsonItem(gsonObj) chapters = gsonObj as VolumeStructure + return pass } override fun onError() { diff --git a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt index 286bcba..dab8c30 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt @@ -49,6 +49,7 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) { override fun onDestroy() { super.onDestroy() //mainWeakReference?.get()?.menuMain?.let { setMenuInvisible(it) } + handler?.downloading = false handler?.mangaDlTools?.exit = true ads.forEach { it.exit = true diff --git a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt index a0c3dc1..c283563 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt @@ -27,7 +27,7 @@ import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.json.ComicStructureOld import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.tools.api.CMApi -import top.fumiama.copymanga.tools.http.MangaDlTools +import top.fumiama.copymanga.manga.MangaDlTools import top.fumiama.copymanga.tools.api.UITools import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json import top.fumiama.copymanga.ui.vm.ViewMangaActivity @@ -48,46 +48,23 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva private var btnw = 0 private var cdwnWidth = 0 private var dl: Dialog? = null - private var hasToastedError = false - get(){ - val re = field - field = true - return re - } private var haveSElectAll = false private var checkedChapter = 0 - private var dldChapter = 0 - private var haveDlStarted = false + private val dldChapter: Int get() = finishMap.count { p -> return@count p == true } private var tbtnlist: Array = arrayOf() private var tbtncnt = 0 private var isNewTitle = false val mangaDlTools = MangaDlTools() private var multiSelect = false - private var size = 0 - private var refreshSize = true private var ltbtn: View? = null - + private var finishMap = arrayOf() + var downloading = false @SuppressLint("SetTextI18n") override fun handleMessage(msg: Message) { super.handleMessage(msg) when(msg.what){ 0 -> dl?.hide() - 1 -> { - tbtnlist[msg.arg1].setBackgroundResource(R.drawable.rndbg_checked) - tbtnlist[msg.arg1].isChecked = false - updateProgressBar() - } - -1 -> { - tbtnlist.get(msg.arg1).setBackgroundResource(R.drawable.rndbg_error) - dldChapter-- - Toast.makeText( - that?.context, - "下载${tbtnlist[msg.arg1].chapterName}失败", - Toast.LENGTH_SHORT - ).show() - updateProgressBar() - } //2 -> scanHiddenChapters() //3 -> 4 -> { @@ -104,7 +81,6 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva } haveSElectAll = false checkedChapter = 0 - dldChapter = 0 } else { for (i in tbtnlist) { if (multiSelect || !i.isChecked && !isChapterExists(i.chapterName, i.caption ?: "null")) { @@ -117,24 +93,12 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva } that?.tdwn?.text = "${dldChapter}/${checkedChapter}" } - 5 -> { - setSize(msg.arg2) - updateProgressBar(msg.arg2, size) - if (!(msg.obj as Boolean)) { - Toast.makeText(that?.context, "下载${tbtnlist.get(msg.arg1).chapterName}的第${msg.arg2}页失败", Toast.LENGTH_SHORT).show() - }else{ - val progressTxt = that?.tdwn?.text.toString() - that?.tdwn?.text = "${progressTxt.substringBefore(' ')} 的 ${msg.arg2}/${size} 页" - } - } 6 -> that?.tdwn?.text = "${dldChapter}/${checkedChapter}" 7 -> deleteChapters(msg.obj as File, msg.arg1) - 8 -> that?.cdwn?.setCardBackgroundColor(that.resources.getColor(R.color.colorBlue)) 9 -> that?.cdwn?.setCardBackgroundColor(that.resources.getColor(R.color.colorGreen)) 10 -> addTbtn(msg.obj as Array) 11 -> addCaption(msg.obj as String) 12 -> addDiv() - 13 -> that?.let { Toast.makeText(it.context, "下载${tbtnlist[msg.arg1].textOn}的第${msg.arg2}页失败,尝试重新下载...", Toast.LENGTH_SHORT).show() } } } @@ -208,16 +172,8 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva File(that?.context?.getExternalFilesDir(""),"$comicName/$caption/$chapter.zip").exists() @SuppressLint("SetTextI18n") private fun updateProgressBar() { - that?.tdwn?.text = "${++dldChapter}/$checkedChapter" - setProgress2(dldChapter * 100 / checkedChapter, 233) - } - private fun updateProgressBar(pageNow: Int, size: Int) { - if(checkedChapter > 0) { - val delta = 100 / checkedChapter - val start = dldChapter * delta - val now = pageNow * delta / size - setProgress2(start + now, 64) - } + that?.tdwn?.text = "$dldChapter/$checkedChapter" + setProgress2(dldChapter * 100 / (if(checkedChapter > 0) checkedChapter else 1), 233) } private fun setProgress2(end: Int, duration: Long) { ObjectAnimator.ofInt( @@ -227,12 +183,6 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva end ).setDuration(duration).start() } - private fun setSize(pageNow: Int){ - if(refreshSize || size == 0) { - size = mangaDlTools.size - refreshSize = false - }else if(pageNow == size) refreshSize = true - } private fun setComponents() { val widthData = toolsBox.calcWidthFromDpRoot(8, 64) btnNumPerRow = widthData[0] @@ -258,23 +208,17 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva else if(checkedChapter == 0) hideDlCard() else{ that.pdwn.progress = 0 - if(haveDlStarted && checkedChapter != 0) mangaDlTools.wait = !mangaDlTools.wait - else { - haveDlStarted = true - mangaDlTools.wait = false - Thread{ - sendEmptyMessage(9) //set dl card color to green - downloadMangas() - sendEmptyMessage(8) //set dl card color to blue - if (!haveDlStarted) { - dldChapter = 0 - checkedChapter = 0 - this.postDelayed({ - setProgress2(0, 233) - that.tdwn?.text = "0/0" - }, 400) - } - }.start() + if (downloading || checkedChapter == 0) { + mangaDlTools.wait = !mangaDlTools.wait!! + } else { + if(!downloading) { + downloading = true + Thread { + sendEmptyMessage(9) + finishMap = arrayOfNulls(tbtnlist.size) + downloadChapterPages() + }.start() + } else mangaDlTools.wait = false } } } @@ -282,46 +226,78 @@ class ComicDlHandler(looper: Looper, that: WeakReference, priva Thread { sendEmptyMessage(4) }.start() return@setOnLongClickListener true } + mangaDlTools.onDownloadedListener = object :MangaDlTools.OnDownloadedListener{ + override fun handleMessage(index: Int, isSuccess: Boolean) { + mainWeakReference?.get()?.runOnUiThread { + if(isSuccess) onZipDownloadFinish(index) + else onZipDownloadFailure(index) + } + } + + override fun handleMessage( + index: Int, + downloaded: Int, + total: Int, + isSuccess: Boolean + ) { + mainWeakReference?.get()?.runOnUiThread { + if(isSuccess) { + tbtnlist[index].text = if(downloaded == 0 && total == 0) tbtnlist[index].chapterName else "$downloaded/$total" + } else { + tbtnlist[index].text = "$downloaded/$total" + Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}的第${downloaded}页失败", Toast.LENGTH_SHORT).show() + } + } + } + } } fun showMultiSelectInfo() { toolsBox.buildInfo("进入多选模式?", "之后可以对已下载漫画进行批量删除/重新下载", "确定", null, "取消", { multiSelect = true }) } - private fun downloadMangas(){ - for (i in tbtnlist) { - if (i.isChecked) downloadChapterPages(i) - } - haveDlStarted = false - } - private fun downloadChapterPages(i: ChapterToggleButton) { - mangaDlTools.onDownloadedListener = - object : MangaDlTools.OnDownloadedListener { - override fun handleMessage(succeed: Boolean) { - this@ComicDlHandler.obtainMessage(if (succeed) 1 else -1, i.index, 0) - .sendToTarget() - } - override fun handleMessage(succeed: Boolean, pageNow: Int) { - this@ComicDlHandler.obtainMessage( - 5, - i.index, - pageNow, - succeed - ).sendToTarget() - } - override fun handleMessage(pageNow: Int){ - this@ComicDlHandler.obtainMessage(13, i.index, pageNow).sendToTarget() + private fun downloadChapterPages() { + tbtnlist.forEach { i -> + if(i.isChecked) { + i.url?.let { + mangaDlTools.downloadChapterInVol( + it, + i.chapterName, + i.caption?:"null", + i.index + ) } } - i.url?.let { - mangaDlTools.downloadChapterInVol( - it, - i.chapterName, - i.caption?:"null", - i.index - ) } } + + private fun onZipDownloadFinish(index: Int) { + if(index >= 0 && index < tbtnlist.size) { + tbtnlist[index].setBackgroundResource(R.drawable.rndbg_checked) + tbtnlist[index].isChecked = false + finishMap[index] = true + updateProgressBar() + that?.apply { + cdwn.postDelayed({ + if (dldChapter == checkedChapter) { + checkedChapter = 0 + setProgress2(0, 233) + tdwn.text = "0/0" + cdwn.setCardBackgroundColor(resources.getColor(R.color.colorBlue)) + finishMap = arrayOf() + downloading = false + } + }, 400) + } + } + } + + private fun onZipDownloadFailure(index: Int) { + tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error) + Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败", Toast.LENGTH_SHORT).show() + updateProgressBar() + } + private fun showDlCard(){ //ObjectAnimator.ofFloat(dlsdwn, "alpha", 0.3f, 0.9f).setDuration(233).start() ObjectAnimator.ofFloat(that?.dlsdwn, "translationX", cdwnWidth.toFloat() * 0.9f, 0f).setDuration(233).start() diff --git a/app/src/main/java/top/fumiama/copymanga/ui/download/DlLHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/download/DlLHandler.kt deleted file mode 100644 index 6fa4c57..0000000 --- a/app/src/main/java/top/fumiama/copymanga/ui/download/DlLHandler.kt +++ /dev/null @@ -1,19 +0,0 @@ -package top.fumiama.copymanga.ui.download - -import android.os.Handler -import android.os.Looper -import android.os.Message -import java.io.File -import java.lang.ref.WeakReference - -class DlLHandler(looper: Looper, dl: DownloadFragment): Handler(looper) { - private val dll = WeakReference(dl) - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - when(msg.what){ - 1 -> dll.get()?.checkDir(msg.obj as File) - 2 -> dll.get()?.rmrf(msg.obj as File) - 3 -> dll.get()?.scanFile(msg.obj as File) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/ui/download/DownloadFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/download/DownloadFragment.kt index 816c387..085a80b 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/download/DownloadFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/download/DownloadFragment.kt @@ -22,16 +22,13 @@ import java.util.zip.ZipInputStream class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) { private var nullZipDirStr = emptyArray() - private var handler: DlLHandler? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) if(isFirstInflate) { arguments?.getString("title")?.let { mainWeakReference?.get()?.toolbar?.title = it } - - handler = DlLHandler(Looper.myLooper()!!, this) - handler?.obtainMessage(3, currentDir)?.sendToTarget() //call scanFile + scanFile(currentDir) } } @@ -71,15 +68,11 @@ class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) { setOnItemLongClickListener { _, _, position, _ -> val chosenFile = File(cd, it[position]) AlertDialog.Builder(context) - .setIcon(R.drawable.ic_launcher_foreground).setMessage("在此执行删除/查错?") - .setTitle("提示").setPositiveButton("删除") { _, _ -> - if (chosenFile.exists()) handler?.obtainMessage(2, chosenFile) - ?.sendToTarget() //call rmrf - handler?.obtainMessage(3, cd)?.sendToTarget() //call scanFile + .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除?") + .setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ -> + if (chosenFile.exists()) rmrf(chosenFile) + scanFile(cd) }.setNegativeButton(android.R.string.cancel) { _, _ -> } - .setNeutralButton("查错") { _, _ -> - handler?.obtainMessage(1, chosenFile)?.sendToTarget() - } //call checkDir .show() true } @@ -98,13 +91,6 @@ class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) { f.delete() } - fun checkDir(f: File){ - nullZipDirStr = emptyArray() - findNullWebpZipFileInDir(f) - if(nullZipDirStr.isNotEmpty()) showErrorZip(nullZipDirStr.joinToString("\n")) - else Toast.makeText(context, "未发现错误", Toast.LENGTH_SHORT).show() - } - private fun callDownloadFragment(jsonFile: File, isNew: Boolean = false){ val bundle = Bundle() Log.d("MyDF", "Call dl and is new: $isNew") diff --git a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt index 534b08d..2f505eb 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt @@ -201,6 +201,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { bundle.putString("path", path_word) rootView?.let { r -> Navigation.findNavController(r).navigate(R.id.action_nav_home_to_nav_book, bundle) } } + holder.itemView.lwc.layoutParams.height = fhs.width / 4 } } diff --git a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt index 35daf08..0756143 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt @@ -78,8 +78,8 @@ class HomeHandler(that: WeakReference) : AutoDownloadHandler( } override fun getGsonItem() = index - override fun setGsonItem(gsonObj: Any) { - super.setGsonItem(gsonObj) + override fun setGsonItem(gsonObj: Any) :Boolean { + val pass = super.setGsonItem(gsonObj) index = gsonObj as IndexStructure var banners = arrayOf() index?.results?.banners?.forEach { @@ -88,6 +88,7 @@ class HomeHandler(that: WeakReference) : AutoDownloadHandler( } } index?.results?.banners = banners + return pass } override fun onError() { super.onError() diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt index ac10035..a4c6f6d 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt @@ -104,11 +104,15 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( 22 -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netinfo } } - override fun getGsonItem() = manga - override fun setGsonItem(gsonObj: Any) { + override fun setGsonItem(gsonObj: Any): Boolean { super.setGsonItem(gsonObj) - manga = gsonObj as Chapter2Return + val m = gsonObj as Chapter2Return + if(m.results.chapter.words.size != m.results.chapter.size) { + return false + } + manga = m + return true } override fun onError() { super.onError() diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt index bcf7fa6..e771b2d 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt @@ -390,18 +390,29 @@ class ViewMangaActivity : TitleActivityTemplate() { private fun getImgBitmap(position: Int): Bitmap? = if (position >= count || position < 0) null - else try { + else { val zip = ZipFile(zipFile) - if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp"))) - else { - val out = ByteArrayOutputStream() - BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out) - BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray())) + try { + if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg"))) + else { + val out = ByteArrayOutputStream() + BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))?.compress(Bitmap.CompressFormat.JPEG, q, out) + BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray())) + } + } catch (e: Exception) { + try { + if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp"))) + else { + val out = ByteArrayOutputStream() + BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out) + BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray())) + } + } catch (e: Exception) { + e.printStackTrace() + Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show() + null + } } - } catch (e: Exception) { - e.printStackTrace() - Toast.makeText(this, "加载zip的${position}.webp错误", Toast.LENGTH_SHORT).show() - null } private fun setIdPosition(position: Int) { diff --git a/app/src/main/res/layout/fragment_download.xml b/app/src/main/res/layout/fragment_download.xml index 451afad..4bf218e 100644 --- a/app/src/main/res/layout/fragment_download.xml +++ b/app/src/main/res/layout/fragment_download.xml @@ -1,11 +1,7 @@ - - - - + android:layout_height="wrap_content" + android:id="@+id/mylv"> + \ No newline at end of file diff --git a/app/src/main/res/layout/line_word.xml b/app/src/main/res/layout/line_word.xml index dd38fbc..70242ff 100644 --- a/app/src/main/res/layout/line_word.xml +++ b/app/src/main/res/layout/line_word.xml @@ -14,6 +14,7 @@ layout="@layout/card_book_plain" android:layout_width="0dp" android:layout_height="0dp" + android:layout_marginStart="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/lwl" app:layout_constraintHorizontal_weight="1" @@ -23,7 +24,8 @@