From aa0190fbb7e404547d9d3e0709605fd30198eb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 16 Mar 2024 23:44:11 +0900 Subject: [PATCH] =?UTF-8?q?v2.2.6=20=E6=96=B0=E5=A2=9E=201.=20=E5=8F=8C?= =?UTF-8?q?=E9=A1=B5=E5=88=87=E5=88=86=E6=98=BE=E7=A4=BA=E9=A2=84=E8=BD=BD?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=202.=20=E9=98=85=E8=A7=88=E6=BC=AB=E7=94=BB?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E6=A0=8F=E6=98=BE=E7=A4=BA=E6=BC=AB=E7=94=BB?= =?UTF-8?q?=E5=90=8D=20=E4=BF=AE=E5=A4=8D=201.=20=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E8=BF=87=E5=A4=9A=E6=BC=AB=E7=94=BB=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=AF=BC=E8=87=B4=E7=9A=84=E9=97=AA=E9=80=80=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=201.=20=E9=98=85=E8=A7=88=E6=BC=AB=E7=94=BB?= =?UTF-8?q?=E5=AE=9A=E4=BD=8D=E9=80=BB=E8=BE=91=202.=20VM=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BC=A0=E9=80=92,=20=E8=B0=83=E7=94=A8=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=203.=20=E7=99=BB=E5=BD=95=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shelved.patch | 2454 ----------------- ...Update_at_2024_3_9__12_23_AM__Changes_.xml | 4 - app/build.gradle | 4 +- .../fumiama/copymanga/manga/MangaDlTools.kt | 8 +- .../top/fumiama/copymanga/manga/Reader.kt | 57 +- .../template/http/PausableDownloader.kt | 6 +- .../copymanga/tools/http/DownloadPool.kt | 148 +- .../copymanga/tools/http/DownloadTools.kt | 11 +- .../fumiama/copymanga/ui/book/BookFragment.kt | 4 +- .../fumiama/copymanga/ui/book/BookHandler.kt | 15 +- .../copymanga/ui/comicdl/ComicDlHandler.kt | 58 +- .../copymanga/ui/download/DownloadFragment.kt | 13 +- .../fumiama/copymanga/ui/vm/PagesManager.kt | 6 +- .../top/fumiama/copymanga/ui/vm/VMHandler.kt | 50 +- .../copymanga/ui/vm/ViewMangaActivity.kt | 122 +- .../java/top/fumiama/copymanga/user/Member.kt | 77 +- app/src/main/res/values/strings.xml | 5 +- 17 files changed, 315 insertions(+), 2727 deletions(-) delete mode 100644 .idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch delete mode 100644 .idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9__12_23_AM__Changes_.xml diff --git a/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch b/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch deleted file mode 100644 index 070c91a..0000000 --- a/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9,_12_23_AM_[Changes]/shelved.patch +++ /dev/null @@ -1,2454 +0,0 @@ -Index: app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.book\n\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.os.Looper\nimport android.os.Message\nimport android.util.Log\nimport android.view.View\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.core.graphics.drawable.toBitmap\nimport androidx.navigation.fragment.findNavController\nimport com.bumptech.glide.Glide\nimport com.bumptech.glide.load.model.GlideUrl\nimport com.bumptech.glide.request.RequestOptions\nimport com.google.gson.Gson\nimport kotlinx.android.synthetic.main.app_bar_main.*\nimport kotlinx.android.synthetic.main.card_book.*\nimport kotlinx.android.synthetic.main.fragment_book.*\nimport kotlinx.android.synthetic.main.line_2chapters.view.*\nimport kotlinx.android.synthetic.main.line_bookinfo.*\nimport kotlinx.android.synthetic.main.line_bookinfo_text.*\nimport kotlinx.android.synthetic.main.line_caption.view.*\nimport kotlinx.android.synthetic.main.line_chapter.view.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.json.BookInfoStructure\nimport top.fumiama.copymanga.json.ChapterStructure\nimport top.fumiama.copymanga.json.ThemeStructure\nimport top.fumiama.copymanga.json.VolumeStructure\nimport top.fumiama.copymanga.manga.Reader\nimport top.fumiama.copymanga.template.http.AutoDownloadHandler\nimport top.fumiama.copymanga.template.http.AutoDownloadThread\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.copymanga.tools.ui.GlideBlurTransformation\nimport top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener\nimport top.fumiama.copymanga.tools.ui.Navigate\nimport top.fumiama.copymanga.ui.comicdl.ComicDlFragment\nimport top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json\nimport top.fumiama.copymanga.ui.vm.ViewMangaActivity\nimport top.fumiama.dmzj.copymanga.R\nimport java.io.File\nimport java.lang.Thread.sleep\nimport java.lang.ref.WeakReference\n\nclass BookHandler(private val th: WeakReference, val path: String)\n : AutoDownloadHandler(th.get()?.getString(R.string.bookInfoApiUrl)?.format(CMApi.myHostApiUrl, path)?: \"\",\n BookInfoStructure::class.java,\n Looper.myLooper()!!){\n private val that get() = th.get()\n private var hasToastedError = false\n get(){\n val re = field\n field = true\n return re\n }\n var book: BookInfoStructure? = null\n private var complete = false\n var ads = emptyArray()\n var gpws = arrayOf()\n var keys = arrayOf()\n var cnts = intArrayOf()\n var vols: Array? = null\n var chapterNames = arrayOf()\n var collect: Int = -1\n private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.fbl, false)\n\n var urlArray = arrayOf()\n\n override fun handleMessage(msg: Message) {\n super.handleMessage(msg)\n when(msg.what){\n //0 -> setLayouts()\n 1 -> setCover()\n 2 -> setTexts()\n 3 -> setAuthorsAndTags()\n //4 -> setOverScale()\n 6 -> if(complete) that?.navigate2dl()\n 7 -> setVolumes()\n 8 -> that?.apply { fbl?.addView(msg.obj as View) }\n 9 -> endSetLayouts()\n }\n }\n\n override fun onError() {\n super.onError()\n if(exit) return\n if(!hasToastedError) that?.activity?.runOnUiThread {\n Toast.makeText(that?.context, R.string.null_book, Toast.LENGTH_SHORT).show()\n that?.apply { findNavController().popBackStack() }\n }\n }\n\n override fun setGsonItem(gsonObj: Any): Boolean {\n val pass = super.setGsonItem(gsonObj)\n book = gsonObj as BookInfoStructure\n return pass\n }\n\n override fun getGsonItem() = book\n override fun doWhenFinishDownload() {\n super.doWhenFinishDownload()\n if(exit) return\n if(keys.isEmpty()) book?.results?.groups?.values?.forEach{\n keys += it.name\n gpws += it.path_word\n if (it.count == 0) {\n it.count = 1\n }\n cnts += it.count\n Log.d(\"MyBFH\", \"Add caption: ${it.name} @ ${it.path_word} of ${it.count}\")\n }\n for (i in 1..4) {\n sendEmptyMessageDelayed(i, (100*i).toLong())\n }\n if(vols?.isEmpty() != false) initComicData()\n }\n\n private fun endSetLayouts() {\n if (exit) return\n that?.fbloading?.apply {\n pauseAnimation()\n visibility = View.GONE\n }\n complete = true\n that?.setStartRead()\n that?.setAddToShelf()\n Log.d(\"MyBH\", \"Set complete: true\")\n }\n\n /*private fun setOverScale() {\n if (exit) return\n that?.fbov?.setScaleView(that!!.fbapp)\n }*/\n\n private fun setCover() {\n if (exit) return\n that?.apply {\n book?.results?.comic?.cover?.let { cover ->\n val load = Glide.with(this).load(\n GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders)\n ).timeout(10000).addListener(GlideHideLottieViewListener(WeakReference(laic)))\n load.into(imic)\n context?.let { it1 -> GlideBlurTransformation(it1) }\n ?.let { it2 -> RequestOptions.bitmapTransform(it2) }\n ?.let { it3 -> load.apply(it3).into(lbibg) }\n }\n imf?.visibility = View.GONE\n //fbl?.addView(divider)\n }\n }\n\n private fun getThemeSeq(authors: Array): CharSequence{\n var re = \"\"\n for(author in authors) re += author.name + ' '\n return re\n }\n\n private fun setTexts(){\n if (exit) return\n //that?.tic?.text = book?.name\n that?.tic?.visibility = View.GONE\n mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name\n that?.btauth?.text = book?.results?.comic?.author?.let { getThemeSeq(it) }\n that?.bttag?.text = book?.results?.comic?.theme?.let { getThemeSeq(it) }\n that?.bthit?.text = that?.getString(R.string.text_format_hit)?.let { String.format(\n it,\n book?.results?.comic?.popular\n ) }?:\"\"\n that?.btsub?.text = that?.getString(R.string.text_format_stat)?.let { String.format(\n it,\n book?.results?.comic?.status?.display\n ) }?:\"\"\n that?.bttime?.text = book?.results?.comic?.datetime_updated\n val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.fbl, false)\n (v as TextView).text = book?.results?.comic?.brief\n that?.fbl?.addView(v)\n that?.fbl?.addView(divider)\n }\n\n private fun setTheme(caption: String, themeStructure: Array, nav: Int) {\n that?.apply {\n val t = layoutInflater.inflate(R.layout.line_caption, fbl, false)\n t.tcptn.text = caption\n fbl.addView(t)\n fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false))\n }\n var line: View? = null\n val last = themeStructure.size - 1\n themeStructure.onEachIndexed { i, it ->\n if(line == null) {\n if(i == last) {\n line = that?.layoutInflater?.inflate(R.layout.line_chapter, that!!.fbl, false)\n line?.lcc?.apply {\n lct.text = it.name\n setOnClickListener { _ ->\n loadVolume(it.name, it.path_word, nav)\n }\n }\n that?.fbl?.addView(line)\n } else {\n line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that!!.fbl, false)\n line?.l2cl?.apply {\n lct.text = it.name\n setOnClickListener { _ ->\n loadVolume(it.name, it.path_word, nav)\n }\n }\n }\n } else line?.l2cr?.apply {\n lct.text = it.name\n setOnClickListener { _ ->\n loadVolume(it.name, it.path_word, nav)\n }\n that?.fbl?.addView(line)\n line = null\n }\n }\n }\n\n private fun setAuthorsAndTags() {\n if (exit) return\n that?.apply {\n book?.results?.comic?.apply {\n author?.let {\n setTheme(\n getString(R.string.author),\n it,\n R.id.action_nav_book_to_nav_author\n )\n }\n fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false))\n theme?.let {\n setTheme(\n getString(R.string.caption),\n it,\n R.id.action_nav_book_to_nav_caption\n )\n }\n }\n }\n }\n\n private fun addVolumesView(v: View) {\n obtainMessage(8, v).sendToTarget()\n }\n\n private fun setVolumes() = Thread {\n if (exit) return@Thread\n that?.apply {\n book?.results?.apply {\n ViewMangaActivity.fileArray = arrayOf()\n urlArray = arrayOf()\n ViewMangaActivity.uuidArray = arrayOf()\n var i = 0\n var last = -1\n vols?.forEachIndexed { groupIndex, v ->\n if(exit) return@Thread\n addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false))\n val t = layoutInflater.inflate(R.layout.line_caption, fbl, false)\n t.tcptn.text = keys[groupIndex]\n addVolumesView(t)\n addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false))\n var line: View? = null\n last += v.results.list.size\n v.results.list.forEach {\n urlArray += CMApi.getChapterInfoApiUrl(\n comic.path_word,\n it.uuid\n )?:\"\"\n ViewMangaActivity.fileArray += CMApi.getZipFile(context?.getExternalFilesDir(\"\"), comic.name, keys[groupIndex], it.name)\n chapterNames += it.name\n ViewMangaActivity.uuidArray += it.uuid\n Log.d(\"MyBH\", \"i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}\")\n that?.isOnPause?.let { isOnPause ->\n while (isOnPause && !exit) sleep(1000)\n if (exit) return@Thread\n }?:return@Thread\n if(line == null) {\n if(i == last) {\n line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false)\n line?.lcc?.apply {\n lct.text = it.name\n Log.d(\"MyBH\", \"add last single chapter ${it.name}\")\n val index = i\n setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }\n }\n line?.let { l -> addVolumesView(l) }\n\n } else {\n line = layoutInflater.inflate(R.layout.line_2chapters, that!!.fbl, false)\n line?.l2cl?.apply {\n lct.text = it.name\n val index = i\n setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }\n }\n }\n } else line?.l2cr?.apply {\n lct.text = it.name\n val index = i\n setOnClickListener { Reader.viewMangaAt(comic.name, index, urlArray) }\n line?.let { l -> addVolumesView(l) }\n line = null\n }\n i++\n }\n }\n sendEmptyMessage(9) // end set layout\n }\n }\n }.start()\n\n private fun loadVolume(name: String, path: String, nav: Int){\n if(complete) {\n Log.d(\"MyBH\", \"start to load chapter\")\n val bundle = Bundle()\n bundle.putString(\"name\", name)\n bundle.putString(\"path\", path)\n that?.apply { Navigate.safeNavigateTo(findNavController(), nav, bundle) }\n }\n }\n\n private fun initComicData() = Thread {\n var volumes = emptyArray()\n val counts = cnts.clone()\n gpws.forEachIndexed { i, gpw ->\n Log.d(\"MyBFH\", \"下载:$gpw\")\n var offset = 0\n val times = counts[i] / 100\n val remain = counts[i] % 100\n val re = arrayOfNulls(if(remain != 0) (times+1) else (times))\n if (re.isEmpty()) that?.activity?.runOnUiThread {\n Toast.makeText(that?.context, \"获取${gpw}失败\", Toast.LENGTH_SHORT).show()\n return@runOnUiThread\n }\n Log.d(\"MyBFH\", \"${i}卷共${if(times == 0) 1 else times}次加载\")\n do {\n counts[i] = counts[i] - 100\n CMApi.getGroupInfoApiUrl(path, gpw, offset)?.let {\n Log.d(\"MyBFH\", \"get api: $it\")\n if(ComicDlFragment.exit) return@Thread\n val ad = AutoDownloadThread(it) { result ->\n val r = Gson().fromJson(result?.decodeToString(), VolumeStructure::class.java)\n re[r.results.offset / 100] = r\n Log.d(\"MyBFH\", \"第${i}卷返回, 大小: ${r.results.list.size}\")\n }\n ads += ad\n ad.start()\n offset += 100\n sleep(1000)\n }\n } while (counts[i] > 0)\n var c = 0\n while (c++ < 80) {\n sleep(1000)\n if(ComicDlFragment.exit) return@Thread\n if(re.all { it != null }) break\n }\n if(re.isNotEmpty()) {\n val r = re[0]\n var s = emptyArray()\n re.forEach {\n it?.results?.list?.forEach {\n s += it\n }\n }\n r?.results?.list = s\n r?.apply { volumes += this }\n } else re[0]?.apply { volumes += this }\n }\n var c = 0\n while (c < 80 && volumes.size != gpws.size) {\n sleep(1000)\n if(ComicDlFragment.exit) return@Thread\n Log.d(\"MyBFH\", \"已有:${volumes.size} 共:${gpws.size}\")\n c++\n }\n if (volumes.size == gpws.size) {\n that?.activity?.runOnUiThread {\n saveVolumes(volumes)\n sendEmptyMessage(7)\n }\n }\n }.start()\n\n private fun saveVolumes(volumes: Array) {\n that?.context?.getExternalFilesDir(\"\")?.let { home ->\n book?.results?.comic?.name?.let { name ->\n val mangaFolder = File(home, name)\n if(!mangaFolder.exists()) mangaFolder.mkdirs()\n json = Gson().toJson(volumes)\n File(mangaFolder, \"info.json\").writeText(json!!)\n File(mangaFolder, \"grps.json\").writeText(Gson().toJson(keys))\n that?.apply {\n Thread {\n var cnt = 0\n var success = false\n while (cnt++ < 10 && !success) {\n sleep(1000)\n if (exit) return@Thread\n File(mangaFolder, \"head.jpg\").let { head ->\n val fo = head.outputStream()\n try {\n imic.drawable.toBitmap().compress(Bitmap.CompressFormat.JPEG, 90, fo)\n success = true\n } catch (e: Exception) {\n e.printStackTrace()\n }\n fo.close()\n }\n }\n if (!success) that?.activity?.runOnUiThread {\n Toast.makeText(that?.context, R.string.download_cover_timeout, Toast.LENGTH_SHORT).show()\n }\n }.start()\n }\n }\n }\n vols = volumes\n }\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -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 ---- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt (date 1709903835374) -@@ -6,13 +6,18 @@ - 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.navigation.fragment.findNavController -+import androidx.recyclerview.widget.RecyclerView - 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.* -@@ -22,6 +27,7 @@ - import kotlinx.android.synthetic.main.line_bookinfo_text.* - import kotlinx.android.synthetic.main.line_caption.view.* - import kotlinx.android.synthetic.main.line_chapter.view.* -+import kotlinx.android.synthetic.main.page_nested_list.view.* - import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.json.BookInfoStructure - import top.fumiama.copymanga.json.ChapterStructure -@@ -62,7 +68,7 @@ - var vols: Array? = null - var chapterNames = arrayOf() - var collect: Int = -1 -- private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.fbl, false) -+ private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.lbl, false) - - var urlArray = arrayOf() - -@@ -73,10 +79,7 @@ - 1 -> setCover() - 2 -> setTexts() - 3 -> setAuthorsAndTags() -- //4 -> setOverScale() - 6 -> if(complete) that?.navigate2dl() -- 7 -> setVolumes() -- 8 -> that?.apply { fbl?.addView(msg.obj as View) } - 9 -> endSetLayouts() - } - } -@@ -127,11 +130,6 @@ - Log.d("MyBH", "Set complete: true") - } - -- /*private fun setOverScale() { -- if (exit) return -- that?.fbov?.setScaleView(that!!.fbapp) -- }*/ -- - private fun setCover() { - if (exit) return - that?.apply { -@@ -144,63 +142,69 @@ - ?.let { it2 -> RequestOptions.bitmapTransform(it2) } - ?.let { it3 -> load.apply(it3).into(lbibg) } - } -- imf?.visibility = View.GONE -+ //imf?.visibility = View.GONE - //fbl?.addView(divider) - } - } - -- private fun getThemeSeq(authors: Array): CharSequence{ -+ /*private fun getThemeSeq(authors: Array): CharSequence{ - var re = "" - for(author in authors) re += author.name + ' ' - return re -- } -+ }*/ - -- private fun setTexts(){ -+ private fun setTexts() { - if (exit) return - //that?.tic?.text = book?.name -- that?.tic?.visibility = View.GONE -+ //that?.tic?.visibility = View.GONE - mainWeakReference?.get()?.toolbar?.title = book?.results?.comic?.name -- that?.btauth?.text = book?.results?.comic?.author?.let { getThemeSeq(it) } -- that?.bttag?.text = book?.results?.comic?.theme?.let { getThemeSeq(it) } -- that?.bthit?.text = that?.getString(R.string.text_format_hit)?.let { String.format( -- it, -+ 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)?.let { String.format( -- it, -+ ) -+ 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?.fbl, false) -+ val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.lbl, false) - (v as TextView).text = book?.results?.comic?.brief -- that?.fbl?.addView(v) -- that?.fbl?.addView(divider) -+ that?.lbl?.addView(v) -+ that?.lbl?.addView(divider) - } - - private fun setTheme(caption: String, themeStructure: Array, nav: Int) { - that?.apply { -- val t = layoutInflater.inflate(R.layout.line_caption, fbl, false) -+ val t = layoutInflater.inflate(R.layout.line_caption, lbl, false) - t.tcptn.text = caption -- fbl.addView(t) -- fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false)) -+ lbl.addView(t) -+ lbl.addView(layoutInflater.inflate(R.layout.div_h, lbl, false)) - } - var line: View? = null - val last = themeStructure.size - 1 - themeStructure.onEachIndexed { i, it -> - if(line == null) { - if(i == last) { -- line = that?.layoutInflater?.inflate(R.layout.line_chapter, that!!.fbl, false) -+ line = that?.layoutInflater?.inflate(R.layout.line_chapter, that!!.lbl, false) - line?.lcc?.apply { - lct.text = it.name -+ lci.setBackgroundResource(R.drawable.ic_list) - setOnClickListener { _ -> - loadVolume(it.name, it.path_word, nav) - } - } -- that?.fbl?.addView(line) -+ that?.lbl?.addView(line) - } else { -- line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that!!.fbl, false) -+ line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that!!.lbl, false) - line?.l2cl?.apply { - lct.text = it.name -+ lci.setBackgroundResource(R.drawable.ic_list) - setOnClickListener { _ -> - loadVolume(it.name, it.path_word, nav) - } -@@ -208,10 +212,11 @@ - } - } else line?.l2cr?.apply { - lct.text = it.name -+ lci.setBackgroundResource(R.drawable.ic_list) - setOnClickListener { _ -> - loadVolume(it.name, it.path_word, nav) - } -- that?.fbl?.addView(line) -+ that?.lbl?.addView(line) - line = null - } - } -@@ -228,7 +233,7 @@ - R.id.action_nav_book_to_nav_author - ) - } -- fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false)) -+ lbl.addView(layoutInflater.inflate(R.layout.div_h, lbl, false)) - theme?.let { - setTheme( - getString(R.string.caption), -@@ -240,36 +245,27 @@ - } - } - -- private fun addVolumesView(v: View) { -- obtainMessage(8, v).sendToTarget() -+ private fun addVolumesView(l: LinearLayout, v: View) { -+ that?.activity?.runOnUiThread { -+ l.addView(v) -+ } - } - -- private fun setVolumes() = Thread { -+ private fun setVolume(fbl: LinearLayout, p: Int) = Thread { - if (exit) return@Thread - that?.apply { - book?.results?.apply { -- ViewMangaActivity.fileArray = arrayOf() -- urlArray = arrayOf() -- ViewMangaActivity.uuidArray = arrayOf() - var i = 0 -- var last = -1 -- vols?.forEachIndexed { groupIndex, v -> -+ for (j in 0 until p) { -+ i += vols?.get(j)?.results?.list?.size?:0 -+ } -+ var last = i-1 -+ vols?.get(p)?.let { v -> - if(exit) return@Thread -- addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false)) -- val t = layoutInflater.inflate(R.layout.line_caption, fbl, false) -- t.tcptn.text = keys[groupIndex] -- addVolumesView(t) -- addVolumesView(layoutInflater.inflate(R.layout.div_h, fbl, false)) - var line: View? = null - last += v.results.list.size - v.results.list.forEach { -- urlArray += CMApi.getChapterInfoApiUrl( -- comic.path_word, -- it.uuid -- )?:"" -- ViewMangaActivity.fileArray += CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[groupIndex], it.name) -- chapterNames += it.name -- ViewMangaActivity.uuidArray += it.uuid -+ val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, 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(1000) -@@ -277,36 +273,70 @@ - }?:return@Thread - if(line == null) { - if(i == last) { -- line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false) -+ line = layoutInflater.inflate(R.layout.line_chapter, fbl, false) - line?.lcc?.apply { - lct.text = it.name -+ 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) } - } -- line?.let { l -> addVolumesView(l) } -- -+ line?.let { l -> addVolumesView(fbl, l) } - } else { -- line = layoutInflater.inflate(R.layout.line_2chapters, that!!.fbl, false) -+ line = layoutInflater.inflate(R.layout.line_2chapters, fbl, false) - line?.l2cl?.apply { - lct.text = it.name -+ if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) - val index = i - setOnClickListener { Reader.viewMangaAt(comic.name, 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) } -- line?.let { l -> addVolumesView(l) } -+ line?.let { l -> addVolumesView(fbl, l) } - line = null - } - i++ - } - } -- sendEmptyMessage(9) // end set layout -- } -- } -+ } -+ } -+ }.start() -+ -+ private fun setViewManga() = Thread { -+ if (exit) return@Thread -+ that?.apply { -+ book?.results?.apply { -+ ViewMangaActivity.fileArray = arrayOf() -+ urlArray = arrayOf() -+ ViewMangaActivity.uuidArray = arrayOf() -+ var i = 0 -+ var last = -1 -+ vols?.forEachIndexed { groupIndex, v -> -+ if(exit) return@Thread -+ last += v.results.list.size -+ v.results.list.forEach { -+ urlArray += CMApi.getChapterInfoApiUrl( -+ comic.path_word, -+ it.uuid -+ )?:"" -+ val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[groupIndex], it.name) -+ ViewMangaActivity.fileArray += f -+ chapterNames += it.name -+ ViewMangaActivity.uuidArray += it.uuid -+ that?.isOnPause?.let { isOnPause -> -+ while (isOnPause && !exit) sleep(1000) -+ if (exit) return@Thread -+ }?:return@Thread -+ i++ -+ } -+ } -+ } -+ } -+ sendEmptyMessage(9) // end set layout - }.start() - - private fun loadVolume(name: String, path: String, nav: Int){ -@@ -375,10 +405,18 @@ - c++ - } - if (volumes.size == gpws.size) { -- that?.activity?.runOnUiThread { -- saveVolumes(volumes) -- sendEmptyMessage(7) -+ saveVolumes(volumes) -+ that?.fbtab?.let { tab -> -+ that?.fbvp?.let { vp -> -+ that?.activity?.runOnUiThread { -+ vp.adapter = ViewData(vp).RecyclerViewAdapter() -+ TabLayoutMediator(tab, vp) { t, p -> -+ t.text = keys[p] -+ }.attach() -+ } -+ } - } -+ setViewManga() - } - }.start() - -@@ -417,4 +455,18 @@ - } - vols = volumes - } -+ -+ inner class ViewData(itemView: View): RecyclerView.ViewHolder(itemView) { -+ inner class RecyclerViewAdapter: RecyclerView.Adapter() { -+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewData { -+ return ViewData(that?.layoutInflater?.inflate(R.layout.page_nested_list, parent, false) as NestedScrollView) -+ } -+ -+ override fun onBindViewHolder(holder: ViewData, position: Int) { -+ setVolume(holder.itemView.fbl, position) -+ } -+ -+ override fun getItemCount(): Int = keys.size -+ } -+ } - } -Index: app/src/main/res/layout/line_bookinfo_text.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n\n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/layout/line_bookinfo_text.xml b/app/src/main/res/layout/line_bookinfo_text.xml ---- a/app/src/main/res/layout/line_bookinfo_text.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/res/layout/line_bookinfo_text.xml (date 1709889795499) -@@ -20,7 +20,7 @@ - android:layout_width="@dimen/icon_size_small" - android:layout_height="@dimen/icon_size_small" - android:layout_marginBottom="@dimen/nav_header_vertical_spacing" -- android:background="@drawable/ic_list" -+ android:background="@drawable/ic_data" - app:layout_constraintBottom_toTopOf="@+id/bitime" - app:layout_constraintEnd_toStartOf="@+id/btsub" - app:layout_constraintStart_toStartOf="parent" -@@ -61,7 +61,7 @@ - android:layout_width="@dimen/icon_size_small" - android:layout_height="@dimen/icon_size_small" - android:layout_marginBottom="@dimen/nav_header_vertical_spacing" -- android:background="@drawable/ic_list" -+ android:background="@drawable/ic_image" - app:layout_constraintBottom_toTopOf="@+id/bihit" - app:layout_constraintEnd_toStartOf="@+id/bttag" - app:layout_constraintStart_toStartOf="parent" -@@ -82,7 +82,7 @@ - android:layout_width="@dimen/icon_size_small" - android:layout_height="@dimen/icon_size_small" - android:layout_marginBottom="@dimen/nav_header_vertical_spacing" -- android:background="@drawable/ic_list" -+ android:background="@drawable/ic_hot" - app:layout_constraintBottom_toTopOf="@+id/bisub" - app:layout_constraintEnd_toStartOf="@+id/bthit" - app:layout_constraintStart_toStartOf="parent" -@@ -103,7 +103,7 @@ - android:layout_width="@dimen/icon_size_small" - android:layout_height="@dimen/icon_size_small" - android:layout_marginBottom="@dimen/nav_header_vertical_spacing" -- android:background="@drawable/ic_author" -+ android:background="@drawable/ic_locate" - app:layout_constraintBottom_toTopOf="@+id/bitag" - app:layout_constraintEnd_toStartOf="@+id/btauth" - app:layout_constraintStart_toStartOf="parent" -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.finish\n\nimport top.fumiama.copymanga.template.ui.StatusCardFlow\nimport top.fumiama.dmzj.copymanga.R\n\n@ExperimentalStdlibApi\nclass FinishFragment : StatusCardFlow(R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book) -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/finish/FinishFragment.kt (date 1709907861461) -@@ -1,7 +1,17 @@ - package top.fumiama.copymanga.ui.cardflow.finish - -+import android.os.Bundle -+import android.view.View - import top.fumiama.copymanga.template.ui.StatusCardFlow - import top.fumiama.dmzj.copymanga.R -+import kotlinx.android.synthetic.main.line_finish.* - - @ExperimentalStdlibApi --class FinishFragment : StatusCardFlow(R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book) -\ No newline at end of file -+class FinishFragment : StatusCardFlow( -+ R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book, R.layout.fragment_statuscardflow) { -+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { -+ super.onViewCreated(view, savedInstanceState) -+ lineUpdate = line_finish_time -+ lineHot = line_finish_pop -+ } -+} -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.newest\n\nimport android.view.View\nimport kotlinx.android.synthetic.main.line_lazybooklines.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.template.ui.InfoCardLoader\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.dmzj.copymanga.R\n\n@ExperimentalStdlibApi\nclass NewestFragment : InfoCardLoader(R.layout.fragment_newest, R.id.action_nav_newest_to_nav_book, true) {\n override fun getApiUrl() =\n getString(R.string.newestApiUrl).format(CMApi.myHostApiUrl, page * 21)\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt (date 1709905749973) -@@ -1,8 +1,5 @@ - package top.fumiama.copymanga.ui.cardflow.newest - --import android.view.View --import kotlinx.android.synthetic.main.line_lazybooklines.* --import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.template.ui.InfoCardLoader - import top.fumiama.copymanga.tools.api.CMApi - import top.fumiama.dmzj.copymanga.R -Index: .idea/dictionaries/fumiama.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n \n \n imgs\n lowpan\n nisi\n \n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/.idea/dictionaries/fumiama.xml b/.idea/dictionaries/fumiama.xml ---- a/.idea/dictionaries/fumiama.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/.idea/dictionaries/fumiama.xml (date 1709884647686) -@@ -4,6 +4,7 @@ - imgs - lowpan - nisi -+ reilia - - - -\ No newline at end of file -Index: app/src/main/res/layout/card_book.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n\n\n \n\n \n\n \n\n \n\n \n\n \n\n \n \n\n \n\n \n\n \n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/layout/card_book.xml b/app/src/main/res/layout/card_book.xml ---- a/app/src/main/res/layout/card_book.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/res/layout/card_book.xml (date 1709904811979) -@@ -78,7 +78,6 @@ - android:layout_marginEnd="16dp" - android:layout_marginBottom="4dp" - android:gravity="center_horizontal" -- android:text="获取标题失败" - android:textAppearance="@style/TextAppearance.AppCompat.Body1" - android:textColor="@android:color/white" - android:textSize="12sp" -Index: app/src/main/java/top/fumiama/copymanga/LoginActivity.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga\n\nimport android.os.Bundle\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.lifecycle.lifecycleScope\nimport kotlinx.android.synthetic.main.activity_login.*\nimport kotlinx.coroutines.launch\nimport top.fumiama.dmzj.copymanga.R\nimport kotlin.random.Random\n\n\nclass LoginActivity : AppCompatActivity() {\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n setContentView(R.layout.activity_login)\n val pref = MainActivity.mainWeakReference?.get()?.getPreferences(MODE_PRIVATE) ?: return\n val isLogout = pref.getString(\"token\", null) != null\n if (isLogout) {\n alblogin.setText(R.string.logout)\n }\n alblogin.setOnClickListener {\n lifecycleScope.launch {\n val salt = Random.nextInt(10000)\n val username = altusrnm.text?.toString() ?: run {\n Toast.makeText(\n this@LoginActivity,\n R.string.login_null_username,\n Toast.LENGTH_SHORT\n ).show()\n return@launch\n }\n val pwd = altpwd.text?.toString() ?: run {\n Toast.makeText(this@LoginActivity, R.string.login_null_pwd, Toast.LENGTH_SHORT)\n .show()\n return@launch\n }\n if (isLogout) {\n MainActivity.member?.logout()\n MainActivity.mainWeakReference?.get()?.refreshUserInfo()\n Toast.makeText(\n this@LoginActivity,\n R.string.login_restart_to_apply,\n Toast.LENGTH_SHORT\n ).show()\n finish()\n return@launch\n }\n val l = MainActivity.member?.login(username, pwd, salt)\n Log.d(\"MyLA\", \"login return code: ${l?.code}\")\n if (l?.code == 200) {\n MainActivity.mainWeakReference?.get()?.refreshUserInfo()\n finish()\n return@launch\n }\n Toast.makeText(this@LoginActivity, l?.message, Toast.LENGTH_SHORT).show()\n }\n }\n }\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/LoginActivity.kt b/app/src/main/java/top/fumiama/copymanga/LoginActivity.kt ---- a/app/src/main/java/top/fumiama/copymanga/LoginActivity.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/LoginActivity.kt (date 1709886202030) -@@ -19,6 +19,7 @@ - val isLogout = pref.getString("token", null) != null - if (isLogout) { - alblogin.setText(R.string.logout) -+ altusrnm.setText(pref.getString("username", "N/A")) - } - alblogin.setOnClickListener { - lifecycleScope.launch { -Index: app/src/main/res/layout/line_chapter.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n\n\n \n\n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/layout/line_chapter.xml b/app/src/main/res/layout/line_chapter.xml ---- a/app/src/main/res/layout/line_chapter.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/res/layout/line_chapter.xml (date 1709899238798) -@@ -15,7 +15,7 @@ - android:layout_marginStart="@dimen/nav_header_vertical_spacing" - android:layout_marginTop="@dimen/nav_header_vertical_spacing" - android:layout_marginBottom="@dimen/nav_header_vertical_spacing" -- android:background="@drawable/ic_list" -+ android:background="@drawable/ic_circle" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.0" -Index: app/src/main/res/drawable-anydpi/ic_success.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/drawable-anydpi/ic_success.xml b/app/src/main/res/drawable-anydpi/ic_success.xml -new file mode 100644 ---- /dev/null (date 1709898923840) -+++ b/app/src/main/res/drawable-anydpi/ic_success.xml (date 1709898923840) -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/MainActivity.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.graphics.Bitmap\nimport android.graphics.BitmapFactory\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Bundle\nimport android.provider.MediaStore\nimport android.util.Log\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.edit\nimport androidx.core.net.toUri\nimport androidx.drawerlayout.widget.DrawerLayout\nimport androidx.navigation.NavController\nimport androidx.navigation.findNavController\nimport androidx.navigation.ui.AppBarConfiguration\nimport androidx.navigation.ui.navigateUp\nimport androidx.navigation.ui.setupActionBarWithNavController\nimport androidx.navigation.ui.setupWithNavController\nimport com.afollestad.materialdialogs.MaterialDialog\nimport com.afollestad.materialdialogs.input.input\nimport com.bumptech.glide.Glide\nimport com.bumptech.glide.load.resource.bitmap.CircleCrop\nimport com.bumptech.glide.request.RequestOptions\nimport com.yalantis.ucrop.UCrop\nimport kotlinx.android.synthetic.main.activity_main.*\nimport kotlinx.android.synthetic.main.app_bar_main.*\nimport kotlinx.android.synthetic.main.nav_header_main.*\nimport top.fumiama.copymanga.manga.Shelf\nimport top.fumiama.copymanga.tools.ui.UITools\nimport top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler\nimport top.fumiama.copymanga.ui.cardflow.rank.RankFragment\nimport top.fumiama.copymanga.ui.comicdl.ComicDlFragment\nimport top.fumiama.copymanga.ui.download.DownloadFragment\nimport top.fumiama.copymanga.ui.download.NewDownloadFragment\nimport top.fumiama.copymanga.update.Update\nimport top.fumiama.copymanga.user.Member\nimport top.fumiama.dmzj.copymanga.BuildConfig\nimport top.fumiama.dmzj.copymanga.R\nimport java.io.File\nimport java.io.FileInputStream\nimport java.lang.Thread.sleep\nimport java.lang.ref.WeakReference\n\nclass MainActivity : AppCompatActivity() {\n private var menuMain: Menu? = null\n private var navController: NavController? = null\n\n private lateinit var appBarConfiguration: AppBarConfiguration\n private lateinit var headPic: File\n lateinit var toolsBox: UITools\n\n private var latestDestination = 0\n private var isMenuWaiting = false\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(null)\n\n // must init before setContentView because HomeF need them to init\n mainWeakReference = WeakReference(this)\n toolsBox = UITools(this)\n\n setContentView(R.layout.activity_main)\n setSupportActionBar(toolbar)\n coordiv.layoutParams.height = UITools.getStatusBarHeight(this)\n\n navController = findNavController(R.id.nav_host_fragment)\n appBarConfiguration = AppBarConfiguration(\n setOf(\n R.id.nav_home,\n R.id.nav_sort,\n R.id.nav_rank,\n R.id.nav_sub,\n R.id.nav_history,\n R.id.nav_new_download,\n R.id.nav_settings\n ), drawer_layout\n )\n setupActionBarWithNavController(navController!!, appBarConfiguration)\n nav_view.setupWithNavController(navController!!)\n\n headPic = File(getExternalFilesDir(\"\"), \"headPic\")\n drawer_layout.addDrawerListener(object : DrawerLayout.DrawerListener {\n override fun onDrawerClosed(drawerView: View) {\n Log.d(\"MyMain\", \"onDrawerClosed\")\n isDrawerClosed = true\n }\n\n override fun onDrawerOpened(drawerView: View) {\n Log.d(\"MyMain\", \"onDrawerOpened\")\n isDrawerClosed = false\n DownloadFragment.currentDir = getExternalFilesDir(\"\")\n refreshUserInfo()\n }\n\n override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}\n override fun onDrawerStateChanged(newState: Int) {}\n })\n checkUpdate(false)\n\n ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager\n\n navController!!.addOnDestinationChangedListener { _, destination, _ ->\n latestDestination = destination.id\n Log.d(\"MyMA\", \"latestDestination: $latestDestination\")\n if (isMenuWaiting) {\n return@addOnDestinationChangedListener\n }\n isMenuWaiting = true\n Log.d(\"MyMA\", \"start menu waiting\")\n Thread {\n sleep(1000)\n isMenuWaiting = false\n Log.d(\"MyMA\", \"finish menu waiting\")\n runOnUiThread {\n when (latestDestination) {\n R.id.nav_home -> {\n Log.d(\"MyMA\", \"enter home\")\n menuMain?.findItem(R.id.action_info)?.isVisible = true\n menuMain?.findItem(R.id.action_download)?.isVisible = false\n menuMain?.findItem(R.id.action_sort)?.isVisible = false\n }\n R.id.nav_book -> {\n Log.d(\"MyMA\", \"enter book\")\n menuMain?.findItem(R.id.action_info)?.isVisible = false\n menuMain?.findItem(R.id.action_download)?.isVisible = true\n menuMain?.findItem(R.id.action_sort)?.isVisible = false\n }\n R.id.nav_group -> {\n Log.d(\"MyMA\", \"enter group\")\n menuMain?.findItem(R.id.action_info)?.isVisible = false\n menuMain?.findItem(R.id.action_download)?.isVisible = false\n menuMain?.findItem(R.id.action_sort)?.isVisible = true\n }\n R.id.nav_new_download -> {\n Log.d(\"MyMA\", \"enter new_download\")\n menuMain?.findItem(R.id.action_info)?.isVisible = false\n menuMain?.findItem(R.id.action_download)?.isVisible = false\n menuMain?.findItem(R.id.action_sort)?.isVisible = true\n }\n R.id.nav_rank -> {\n Log.d(\"MyMA\", \"enter rank\")\n menuMain?.findItem(R.id.action_info)?.isVisible = false\n menuMain?.findItem(R.id.action_download)?.isVisible = false\n menuMain?.findItem(R.id.action_sort)?.isVisible = true\n }\n else -> {\n Log.d(\"MyMA\", \"enter others\")\n menuMain?.findItem(R.id.action_info)?.isVisible = false\n menuMain?.findItem(R.id.action_download)?.isVisible = false\n menuMain?.findItem(R.id.action_sort)?.isVisible = false\n }\n }\n }\n }.start()\n }\n }\n\n override fun onCreateOptionsMenu(menu: Menu): Boolean {\n // Inflate the menu; this adds items to the action bar if it is present.\n menuInflater.inflate(R.menu.main, menu)\n menuMain = menu\n return true\n }\n\n @OptIn(ExperimentalStdlibApi::class)\n override fun onOptionsItemSelected(item: MenuItem): Boolean {\n return when (item.itemId) {\n R.id.action_info -> {\n showAbout()\n true\n }\n R.id.action_download -> {\n bookHandler?.sendEmptyMessage(6)\n true\n }\n R.id.action_sort -> {\n ComicDlFragment.handler?.sendEmptyMessage(13)\n NewDownloadFragment.wn?.get()?.showReverseInfo(toolsBox)\n RankFragment.wr?.get()?.showSexInfo(toolsBox)\n true\n }\n else -> super.onOptionsItemSelected(item)\n }\n }\n\n override fun onSupportNavigateUp(): Boolean {\n val navController = findNavController(R.id.nav_host_fragment)\n\n checkHeadPicture()\n if (headPic.exists()) navhbg.setOnLongClickListener {\n if (headPic.exists()) {\n val dl = AlertDialog.Builder(this)\n dl.setMessage(R.string.clearHeadImgMsg)\n dl.setPositiveButton(android.R.string.ok) { _, _ ->\n if (headPic.exists()) headPic.delete()\n navhbg.setImageResource(R.drawable.illust_57793944_20190427_134853)\n }\n dl.show()\n }\n true\n }\n navtinfo.text = getPreferences(MODE_PRIVATE).getString(\"navTextInfo\", getString(R.string.navTextInfo))\n return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()\n }\n\n @Deprecated(\"Deprecated in Java\")\n override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n super.onActivityResult(requestCode, resultCode, data)\n if (resultCode == RESULT_OK) when (requestCode) {\n UCrop.REQUEST_CROP -> {\n val fi = headPic.inputStream()\n navhbg.setImageBitmap(BitmapFactory.decodeStream(fi))\n fi.close()\n }\n MSG_CROP_IMAGE -> {\n data?.data?.let {\n saveFile(it)\n cropImageUri()\n }\n }\n }\n }\n\n override fun onRequestPermissionsResult(\n requestCode: Int,\n permissions: Array,\n grantResults: IntArray\n ) {\n super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n when (requestCode) {\n MSG_CROP_IMAGE -> {\n if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) pickPicture()\n else Toast.makeText(this, R.string.permissionDenied, Toast.LENGTH_SHORT).show()\n }\n }\n }\n\n fun refreshUserInfo() {\n getPreferences(MODE_PRIVATE)?.apply {\n val name = getString(\"nickname\", getString(\"username\", \"\"))\n val avatar = getString(\"avatar\", \"\")\n if(name != \"\") navttitle.text = name\n else navttitle.setText(R.string.noLogin)\n if(avatar != \"\")\n Glide.with(this@MainActivity).load(avatar)\n .apply(RequestOptions.bitmapTransform(CircleCrop()))\n .into(navhicon)\n }\n }\n\n private fun checkReadPermission(): Boolean {\n return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && ContextCompat.checkSelfPermission(\n this,\n Manifest.permission.READ_EXTERNAL_STORAGE\n ) != PackageManager.PERMISSION_GRANTED\n ) {\n ActivityCompat.requestPermissions(\n this,\n arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), MSG_CROP_IMAGE\n )\n false\n } else true\n }\n\n @SuppressLint(\"IntentReset\")\n private fun pickPicture() {\n val i = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)\n i.type = \"image/*\"\n startActivityForResult(i, MSG_CROP_IMAGE)\n }\n\n private fun saveFile(uri: Uri) {\n //val f = File(getExternalFilesDir(\"\"), \"headPic\")\n val fd = contentResolver.openFileDescriptor(uri, \"r\")\n fd?.fileDescriptor?.let {\n val fi = FileInputStream(it)\n val fo = headPic.outputStream()\n fi.copyTo(fo)\n fi.close()\n fo.close()\n }\n fd?.close()\n }\n\n private fun checkHeadPicture() {\n //val hp = File(getExternalFilesDir(\"\"), \"headPic\")\n if (headPic.exists()) navhbg.setImageURI(headPic.toUri())\n }\n\n private fun cropImageUri() {\n val op = UCrop.Options()\n val r = navhbg.width.toFloat() / navhbg.height.toFloat()\n Log.d(\"MyMain\", \"Img info: (${navhbg.width}, ${navhbg.height})\")\n Log.d(\"MyMain\", \"Result code: ${UCrop.REQUEST_CROP}\")\n if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n op.setCompressionFormat(Bitmap.CompressFormat.WEBP_LOSSY)\n } else {\n op.setCompressionFormat(Bitmap.CompressFormat.WEBP)\n }\n op.setStatusBarColor(resources.getColor(R.color.colorPrimaryDark, theme))\n op.setToolbarColor(resources.getColor(R.color.colorPrimary, theme))\n op.setActiveControlsWidgetColor(resources.getColor(R.color.colorAccent, theme))\n UCrop.of(headPic.toUri(), headPic.toUri())\n .withAspectRatio(r, 1F)\n .withMaxResultSize(navhbg.width, navhbg.height)\n .withOptions(op)\n .start(this)\n }\n\n private fun checkUpdate(ignoreSkip: Boolean) {\n Thread{\n Update.checkUpdate(this, toolsBox, ignoreSkip)\n }.start()\n }\n\n private fun showAbout() {\n val dl = android.app.AlertDialog.Builder(this)\n dl.setMessage(R.string.app_description)\n dl.setTitle(\"${getString(R.string.action_info)} ${BuildConfig.VERSION_NAME}\")\n dl.setIcon(R.mipmap.ic_launcher)\n dl.setPositiveButton(android.R.string.ok) { _, _ -> }\n dl.setNeutralButton(R.string.check_update) {_, _ ->\n checkUpdate(true)\n }\n dl.show()\n }\n\n @SuppressLint(\"CheckResult\")\n fun onNavTInfoClicked(it: View) {\n MaterialDialog(this).show {\n input(prefill = (it as TextView).text) { _, charSequence ->\n it.text = charSequence\n getPreferences(MODE_PRIVATE).edit {\n putString(\"navTextInfo\", charSequence.toString())\n apply()\n }\n }\n positiveButton(android.R.string.ok)\n title(R.string.navTextInfoInputHint)\n }\n }\n\n fun onNavHBgClicked(v: View) {\n if (checkReadPermission()) pickPicture()\n }\n\n fun startLoginActivity(v: View){\n startActivity(Intent(this, LoginActivity::class.java))\n }\n\n companion object{\n var mainWeakReference: WeakReference? = null\n var isDrawerClosed = true\n var ime: InputMethodManager? = null\n const val MSG_CROP_IMAGE = 1\n var shelf: Shelf? = null\n get() {\n if (field != null) return field\n return mainWeakReference?.get()?.let {\n field = Shelf(\n it.getPreferences(Context.MODE_PRIVATE)\n .getString(\"token\", \"\")?:return@let null) { id ->\n return@Shelf it.getString(id)\n }\n field\n }\n }\n var member: Member? = null\n get() {\n if (field != null) return field\n return mainWeakReference?.get()?.let {\n it.getPreferences(MODE_PRIVATE)?.let { pref ->\n field = Member(pref) { id ->\n return@Member it.getString(id)\n }\n }\n field\n }\n }\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt ---- a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt (date 1709887113979) -@@ -2,6 +2,7 @@ - - import android.Manifest - import android.annotation.SuppressLint -+import android.app.Activity - import android.content.Context - import android.content.Intent - import android.content.pm.PackageManager -@@ -18,6 +19,7 @@ - import android.view.inputmethod.InputMethodManager - import android.widget.TextView - import android.widget.Toast -+import androidx.activity.result.contract.ActivityResultContracts - import androidx.appcompat.app.AlertDialog - import androidx.appcompat.app.AppCompatActivity - import androidx.core.app.ActivityCompat -@@ -25,6 +27,7 @@ - import androidx.core.content.edit - import androidx.core.net.toUri - import androidx.drawerlayout.widget.DrawerLayout -+import androidx.lifecycle.lifecycleScope - import androidx.navigation.NavController - import androidx.navigation.findNavController - import androidx.navigation.ui.AppBarConfiguration -@@ -40,6 +43,9 @@ - import kotlinx.android.synthetic.main.activity_main.* - import kotlinx.android.synthetic.main.app_bar_main.* - import kotlinx.android.synthetic.main.nav_header_main.* -+import kotlinx.coroutines.Dispatchers -+import kotlinx.coroutines.launch -+import kotlinx.coroutines.withContext - import top.fumiama.copymanga.manga.Shelf - import top.fumiama.copymanga.tools.ui.UITools - import top.fumiama.copymanga.ui.book.BookFragment.Companion.bookHandler -@@ -64,7 +70,6 @@ - private lateinit var headPic: File - lateinit var toolsBox: UITools - -- private var latestDestination = 0 - private var isMenuWaiting = false - - override fun onCreate(savedInstanceState: Bundle?) { -@@ -114,6 +119,7 @@ - - ime = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - -+ var latestDestination: Int - navController!!.addOnDestinationChangedListener { _, destination, _ -> - latestDestination = destination.id - Log.d("MyMA", "latestDestination: $latestDestination") -@@ -122,51 +128,16 @@ - } - isMenuWaiting = true - Log.d("MyMA", "start menu waiting") -- Thread { -- sleep(1000) -- isMenuWaiting = false -- Log.d("MyMA", "finish menu waiting") -- runOnUiThread { -- when (latestDestination) { -- R.id.nav_home -> { -- Log.d("MyMA", "enter home") -- menuMain?.findItem(R.id.action_info)?.isVisible = true -- menuMain?.findItem(R.id.action_download)?.isVisible = false -- menuMain?.findItem(R.id.action_sort)?.isVisible = false -- } -- R.id.nav_book -> { -- Log.d("MyMA", "enter book") -- menuMain?.findItem(R.id.action_info)?.isVisible = false -- menuMain?.findItem(R.id.action_download)?.isVisible = true -- menuMain?.findItem(R.id.action_sort)?.isVisible = false -- } -- R.id.nav_group -> { -- Log.d("MyMA", "enter group") -- menuMain?.findItem(R.id.action_info)?.isVisible = false -- menuMain?.findItem(R.id.action_download)?.isVisible = false -- menuMain?.findItem(R.id.action_sort)?.isVisible = true -- } -- R.id.nav_new_download -> { -- Log.d("MyMA", "enter new_download") -- menuMain?.findItem(R.id.action_info)?.isVisible = false -- menuMain?.findItem(R.id.action_download)?.isVisible = false -- menuMain?.findItem(R.id.action_sort)?.isVisible = true -- } -- R.id.nav_rank -> { -- Log.d("MyMA", "enter rank") -- menuMain?.findItem(R.id.action_info)?.isVisible = false -- menuMain?.findItem(R.id.action_download)?.isVisible = false -- menuMain?.findItem(R.id.action_sort)?.isVisible = true -- } -- else -> { -- Log.d("MyMA", "enter others") -- menuMain?.findItem(R.id.action_info)?.isVisible = false -- menuMain?.findItem(R.id.action_download)?.isVisible = false -- menuMain?.findItem(R.id.action_sort)?.isVisible = false -- } -- } -- } -- }.start() -+ lifecycleScope.launch { -+ withContext(Dispatchers.IO) { -+ sleep(1000) -+ withContext(Dispatchers.Main) { -+ isMenuWaiting = false -+ Log.d("MyMA", "finish menu waiting") -+ changeMenuList(latestDestination) -+ } -+ } -+ } - } - } - -@@ -218,24 +189,6 @@ - return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() - } - -- @Deprecated("Deprecated in Java") -- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { -- super.onActivityResult(requestCode, resultCode, data) -- if (resultCode == RESULT_OK) when (requestCode) { -- UCrop.REQUEST_CROP -> { -- val fi = headPic.inputStream() -- navhbg.setImageBitmap(BitmapFactory.decodeStream(fi)) -- fi.close() -- } -- MSG_CROP_IMAGE -> { -- data?.data?.let { -- saveFile(it) -- cropImageUri() -- } -- } -- } -- } -- - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, -@@ -263,6 +216,47 @@ - } - } - -+ private fun changeMenuList(latestDestination: Int) { -+ when (latestDestination) { -+ R.id.nav_home -> { -+ Log.d("MyMA", "enter home") -+ menuMain?.findItem(R.id.action_info)?.isVisible = true -+ menuMain?.findItem(R.id.action_download)?.isVisible = false -+ menuMain?.findItem(R.id.action_sort)?.isVisible = false -+ } -+ R.id.nav_book -> { -+ Log.d("MyMA", "enter book") -+ menuMain?.findItem(R.id.action_info)?.isVisible = false -+ menuMain?.findItem(R.id.action_download)?.isVisible = true -+ menuMain?.findItem(R.id.action_sort)?.isVisible = false -+ } -+ R.id.nav_group -> { -+ Log.d("MyMA", "enter group") -+ menuMain?.findItem(R.id.action_info)?.isVisible = false -+ menuMain?.findItem(R.id.action_download)?.isVisible = false -+ menuMain?.findItem(R.id.action_sort)?.isVisible = true -+ } -+ R.id.nav_new_download -> { -+ Log.d("MyMA", "enter new_download") -+ menuMain?.findItem(R.id.action_info)?.isVisible = false -+ menuMain?.findItem(R.id.action_download)?.isVisible = false -+ menuMain?.findItem(R.id.action_sort)?.isVisible = true -+ } -+ R.id.nav_rank -> { -+ Log.d("MyMA", "enter rank") -+ menuMain?.findItem(R.id.action_info)?.isVisible = false -+ menuMain?.findItem(R.id.action_download)?.isVisible = false -+ menuMain?.findItem(R.id.action_sort)?.isVisible = true -+ } -+ else -> { -+ Log.d("MyMA", "enter others") -+ menuMain?.findItem(R.id.action_info)?.isVisible = false -+ menuMain?.findItem(R.id.action_download)?.isVisible = false -+ menuMain?.findItem(R.id.action_sort)?.isVisible = false -+ } -+ } -+ } -+ - private fun checkReadPermission(): Boolean { - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && ContextCompat.checkSelfPermission( - this, -@@ -277,11 +271,18 @@ - } else true - } - -+ private var pickerLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> -+ if (result.resultCode == Activity.RESULT_OK) result.data?.data?.let { -+ saveFile(it) -+ cropImageUri() -+ } else Toast.makeText(this, R.string.err_pick_img, Toast.LENGTH_SHORT).show() -+ } -+ - @SuppressLint("IntentReset") - private fun pickPicture() { - val i = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) - i.type = "image/*" -- startActivityForResult(i, MSG_CROP_IMAGE) -+ pickerLauncher.launch(i) - } - - private fun saveFile(uri: Uri) { -@@ -302,11 +303,18 @@ - if (headPic.exists()) navhbg.setImageURI(headPic.toUri()) - } - -+ private var cropLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> -+ if (result.resultCode == Activity.RESULT_OK) { -+ val fi = headPic.inputStream() -+ navhbg.setImageBitmap(BitmapFactory.decodeStream(fi)) -+ fi.close() -+ } else Toast.makeText(this, R.string.err_crop_img, Toast.LENGTH_SHORT).show() -+ } -+ - private fun cropImageUri() { - val op = UCrop.Options() - val r = navhbg.width.toFloat() / navhbg.height.toFloat() - Log.d("MyMain", "Img info: (${navhbg.width}, ${navhbg.height})") -- Log.d("MyMain", "Result code: ${UCrop.REQUEST_CROP}") - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - op.setCompressionFormat(Bitmap.CompressFormat.WEBP_LOSSY) - } else { -@@ -315,17 +323,17 @@ - op.setStatusBarColor(resources.getColor(R.color.colorPrimaryDark, theme)) - op.setToolbarColor(resources.getColor(R.color.colorPrimary, theme)) - op.setActiveControlsWidgetColor(resources.getColor(R.color.colorAccent, theme)) -- UCrop.of(headPic.toUri(), headPic.toUri()) -+ cropLauncher.launch(UCrop.of(headPic.toUri(), headPic.toUri()) - .withAspectRatio(r, 1F) - .withMaxResultSize(navhbg.width, navhbg.height) - .withOptions(op) -- .start(this) -+ .getIntent(this)) - } - - private fun checkUpdate(ignoreSkip: Boolean) { -- Thread{ -- Update.checkUpdate(this, toolsBox, ignoreSkip) -- }.start() -+ lifecycleScope.launch { -+ Update.checkUpdate(this@MainActivity, toolsBox, ignoreSkip) -+ } - } - - private fun showAbout() { -Index: app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.download\n\nimport android.app.AlertDialog\nimport android.content.Intent\nimport android.os.Bundle\nimport android.provider.DocumentsContract\nimport android.util.Log\nimport android.view.View\nimport android.widget.Toast\nimport androidx.core.content.FileProvider\nimport androidx.core.net.toUri\nimport androidx.fragment.app.Fragment\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport kotlinx.android.synthetic.main.line_lazybooklines.*\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.manga.Reader\nimport top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate\nimport top.fumiama.copymanga.template.ui.CardList\nimport top.fumiama.copymanga.tools.ui.Navigate\nimport top.fumiama.copymanga.tools.ui.UITools\nimport top.fumiama.copymanga.tools.file.FileUtils\nimport top.fumiama.copymanga.ui.comicdl.ComicDlFragment\nimport top.fumiama.dmzj.copymanga.R\nimport java.io.File\nimport java.lang.Thread.sleep\nimport java.lang.ref.WeakReference\n\n@OptIn(ExperimentalStdlibApi::class)\nclass NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownload, forceLoad = true) {\n private var sortedBookList: List? = null\n private val oldDlCardName = MainActivity.mainWeakReference?.get()?.getString(R.string.old_download_card_name)!!\n private val extDir = MainActivity.mainWeakReference?.get()?.getExternalFilesDir(\"\")\n private var isReverse = false\n private var isContentChanged = false\n private var exit = false\n private var showAll = false\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n wn = WeakReference(this)\n val settingsPref = MainActivity.mainWeakReference?.get()?.let { PreferenceManager.getDefaultSharedPreferences(it) }\n showAll = settingsPref?.getBoolean(\"settings_cat_md_sw_show_0m_manga\", false)?:false\n }\n\n override fun onPause() {\n super.onPause()\n exit = true\n }\n\n override fun onResume() {\n super.onResume()\n exit = false\n }\n\n override fun onDestroy() {\n super.onDestroy()\n wn = null\n exit = true\n }\n\n override fun addPage() {\n super.addPage()\n if(isRefresh){\n page = 0\n isRefresh = false\n }\n if(!isEnd) {\n if(sortedBookList == null || isContentChanged) {\n Log.d(\"MyNDF\", \"Sorting books...\")\n sortedBookList = extDir?.listFiles()?.sortedBy {\n return@sortedBy Reader.getComicPathWordInFile(it)\n }\n if (isReverse) {\n Log.d(\"MyNDF\", \"reversed...\")\n sortedBookList = sortedBookList?.asReversed()\n }\n if (!showAll) {\n sortedBookList = sortedBookList?.filter {\n return@filter FileUtils.sizeOf(it) / 1048576 > 0\n }\n }\n isContentChanged = false\n }\n Log.d(\"MyNDF\", \"Start drawing cards\")\n cardList?.addCard(oldDlCardName, path = oldDlCardName)\n var cnt = 1\n sortedBookList?.let {\n for(i in it.listIterator(page)) {\n if(cardList?.exitCardList != false) return\n page++ // page is actually count\n val chosenJson = File(i, \"info.bin\")\n val newJson = File(i, \"info.json\")\n val bookSize = (FileUtils.sizeOf(i)/1048576).toInt()\n when {\n chosenJson.exists() -> continue // unsupported old folder\n newJson.exists() -> {\n if(cardList?.exitCardList != false) return\n cardList?.addCard(i.name, \"\\n${bookSize}MB\")\n cnt++\n }\n }\n if (cnt >= 21) break\n }\n if(page >= it.size) {\n isEnd = true\n }\n }\n }\n onLoadFinish()\n }\n\n override fun initCardList(weakReference: WeakReference) {\n super.initCardList(weakReference)\n cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)\n cardList?.initClickListeners = object : CardList.InitClickListeners {\n override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {\n v.setOnClickListener {\n if(name==oldDlCardName && path == oldDlCardName) {\n Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_download)\n return@setOnClickListener\n }\n callDownloadFragment(name)\n }\n v.setOnLongClickListener {\n if (name == oldDlCardName && path == oldDlCardName) {\n return@setOnLongClickListener false\n }\n val chosenFile = File(extDir, name)\n AlertDialog.Builder(context)\n .setIcon(R.drawable.ic_launcher_foreground)\n .setTitle(R.string.new_download_card_option_hint)\n .setItems(arrayOf(\"删除数据\", \"前往详情\")) { d, p ->\n d.cancel()\n when (p) {\n 0 -> {\n AlertDialog.Builder(context)\n .setIcon(R.drawable.ic_launcher_foreground).setMessage(\"删除下载的漫画${name}吗?\")\n .setTitle(\"提示\").setPositiveButton(android.R.string.ok) { _, _ ->\n if (chosenFile.exists()) Thread {\n FileUtils.recursiveRemove(chosenFile)\n activity?.runOnUiThread {\n it.visibility = View.INVISIBLE\n }\n }.start()\n }.setNegativeButton(android.R.string.cancel) { _, _ -> }\n .show()\n }\n 1 -> {\n val bundle = Bundle()\n bundle.putBoolean(\"loadJson\", true)\n bundle.putString(\"name\", name)\n Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_book, bundle)\n }\n }\n }\n .show()\n\n true\n }\n }\n }\n }\n\n private fun callDownloadFragment(name: String){\n val bundle = Bundle()\n Log.d(\"MyNDF\", \"Call dl and is new.\")\n bundle.putBoolean(\"loadJson\", true)\n bundle.putString(\"name\", name)\n ComicDlFragment.json = File(File(extDir, name), \"info.json\").readText()\n Log.d(\"MyNDF\", \"root view: $rootView\")\n Log.d(\"MyNDF\", \"action_nav_new_download_to_nav_group\")\n Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_group, bundle)\n }\n\n fun showReverseInfo(toolsBox: UITools) {\n if (exit) return\n toolsBox.buildInfo(\"反转排序\", \"将按当前顺序的倒序显示下载的漫画\",\n \"确定\", null, \"取消\", {\n isReverse = !isReverse\n isContentChanged = true\n reset()\n Thread {\n sleep(600)\n addPage()\n }.start()\n }\n )\n }\n\n override fun onLoadFinish() {\n super.onLoadFinish()\n activity?.runOnUiThread {\n mypl.visibility = View.GONE\n }\n }\n\n companion object {\n var wn: WeakReference? = null\n }\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt (date 1709909463888) -@@ -10,9 +10,13 @@ - import androidx.core.content.FileProvider - import androidx.core.net.toUri - import androidx.fragment.app.Fragment -+import androidx.lifecycle.lifecycleScope - import androidx.navigation.fragment.findNavController - import androidx.preference.PreferenceManager - import kotlinx.android.synthetic.main.line_lazybooklines.* -+import kotlinx.coroutines.Dispatchers -+import kotlinx.coroutines.launch -+import kotlinx.coroutines.withContext - import top.fumiama.copymanga.MainActivity - import top.fumiama.copymanga.manga.Reader - import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate -@@ -64,49 +68,53 @@ - page = 0 - isRefresh = false - } -- if(!isEnd) { -- if(sortedBookList == null || isContentChanged) { -- Log.d("MyNDF", "Sorting books...") -- sortedBookList = extDir?.listFiles()?.sortedBy { -- return@sortedBy Reader.getComicPathWordInFile(it) -- } -- if (isReverse) { -- Log.d("MyNDF", "reversed...") -- sortedBookList = sortedBookList?.asReversed() -- } -- if (!showAll) { -- sortedBookList = sortedBookList?.filter { -- return@filter FileUtils.sizeOf(it) / 1048576 > 0 -- } -- } -- isContentChanged = false -- } -- Log.d("MyNDF", "Start drawing cards") -- cardList?.addCard(oldDlCardName, path = oldDlCardName) -- var cnt = 1 -- sortedBookList?.let { -- for(i in it.listIterator(page)) { -- if(cardList?.exitCardList != false) return -- page++ // page is actually count -- val chosenJson = File(i, "info.bin") -- val newJson = File(i, "info.json") -- val bookSize = (FileUtils.sizeOf(i)/1048576).toInt() -- when { -- chosenJson.exists() -> continue // unsupported old folder -- newJson.exists() -> { -- if(cardList?.exitCardList != false) return -- cardList?.addCard(i.name, "\n${bookSize}MB") -- cnt++ -- } -- } -- if (cnt >= 21) break -- } -- if(page >= it.size) { -- isEnd = true -- } -- } -- } -- onLoadFinish() -+ lifecycleScope.launch { -+ withContext(Dispatchers.IO) { -+ if(!isEnd) { -+ if(sortedBookList == null || isContentChanged) { -+ Log.d("MyNDF", "Sorting books...") -+ sortedBookList = extDir?.listFiles()?.sortedBy { -+ return@sortedBy Reader.getComicPathWordInFile(it) -+ } -+ if (isReverse) { -+ Log.d("MyNDF", "reversed...") -+ sortedBookList = sortedBookList?.asReversed() -+ } -+ if (!showAll) { -+ sortedBookList = sortedBookList?.filter { -+ return@filter FileUtils.sizeOf(it) / 1048576 > 0 -+ } -+ } -+ isContentChanged = false -+ } -+ Log.d("MyNDF", "Start drawing cards") -+ cardList?.addCard(oldDlCardName, path = oldDlCardName) -+ var cnt = 1 -+ sortedBookList?.let { -+ for(i in it.listIterator(page)) { -+ if(cardList?.exitCardList != false) return@withContext -+ page++ // page is actually count -+ val chosenJson = File(i, "info.bin") -+ val newJson = File(i, "info.json") -+ val bookSize = (FileUtils.sizeOf(i)/1048576).toInt() -+ when { -+ chosenJson.exists() -> continue // unsupported old folder -+ newJson.exists() -> { -+ if(cardList?.exitCardList != false) return@withContext -+ cardList?.addCard(i.name, "\n${bookSize}MB") -+ cnt++ -+ } -+ } -+ if (cnt >= 21) break -+ } -+ if(page >= it.size) { -+ isEnd = true -+ } -+ } -+ } -+ onLoadFinish() -+ } -+ } - } - - override fun initCardList(weakReference: WeakReference) { -@@ -136,12 +144,14 @@ - AlertDialog.Builder(context) - .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画${name}吗?") - .setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ -> -- if (chosenFile.exists()) Thread { -- FileUtils.recursiveRemove(chosenFile) -- activity?.runOnUiThread { -- it.visibility = View.INVISIBLE -+ if (chosenFile.exists()) lifecycleScope.launch { -+ withContext(Dispatchers.IO) { -+ FileUtils.recursiveRemove(chosenFile) -+ withContext(Dispatchers.Main) { -+ it.visibility = View.INVISIBLE -+ } - } -- }.start() -+ } - }.setNegativeButton(android.R.string.cancel) { _, _ -> } - .show() - } -Index: app/src/main/res/layout/line_bookinfo.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n\n\n \n\n \n\n \n\n \n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/layout/line_bookinfo.xml b/app/src/main/res/layout/line_bookinfo.xml ---- a/app/src/main/res/layout/line_bookinfo.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/res/layout/line_bookinfo.xml (date 1709897914592) -@@ -27,22 +27,32 @@ - layout="@layout/card_book" - android:layout_width="@dimen/book_card_width" - android:layout_height="0dp" -- app:layout_constraintBottom_toBottomOf="parent" -+ app:layout_constraintBottom_toBottomOf="@+id/lbitb" - app:layout_constraintEnd_toStartOf="@+id/lbitb" - app:layout_constraintHorizontal_weight="1" - app:layout_constraintStart_toStartOf="parent" -- app:layout_constraintTop_toTopOf="parent" -- app:layout_constraintVertical_bias="0.499" /> -+ app:layout_constraintTop_toTopOf="parent" /> - - -+ -+ - - -\ No newline at end of file -Index: build.gradle -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n ext.kotlin_version = '1.7.10'\n repositories {\n google()\n jcenter()\n mavenCentral()\n mavenCentral()\n maven { url 'https://maven.google.com' }\n maven { url \"https://jitpack.io\" }\n }\n dependencies {\n classpath 'com.android.tools.build:gradle:8.1.1'\n classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n // NOTE: Do not place your application dependencies here; they belong\n // in the individual module build.gradle files\n }\n}\n\nallprojects {\n repositories {\n google()\n jcenter()\n mavenCentral()\n maven { url \"https://jitpack.io\" }\n }\n}\n\ntask clean(type: Delete) {\n delete rootProject.buildDir\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/build.gradle b/build.gradle ---- a/build.gradle (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/build.gradle (date 1709881875422) -@@ -10,7 +10,7 @@ - maven { url "https://jitpack.io" } - } - dependencies { -- classpath 'com.android.tools.build:gradle:8.1.1' -+ classpath 'com.android.tools.build:gradle:8.2.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - - // NOTE: Do not place your application dependencies here; they belong -@@ -27,6 +27,6 @@ - } - } - --task clean(type: Delete) { -+tasks.register('clean', Delete) { - delete rootProject.buildDir - } -Index: app/src/main/res/drawable-anydpi/ic_circle.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/drawable-anydpi/ic_circle.xml b/app/src/main/res/drawable-anydpi/ic_circle.xml -new file mode 100644 ---- /dev/null (date 1709899198517) -+++ b/app/src/main/res/drawable-anydpi/ic_circle.xml (date 1709899198517) -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -\ No newline at end of file -Index: app/src/main/res/layout/page_nested_list.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/layout/page_nested_list.xml b/app/src/main/res/layout/page_nested_list.xml -new file mode 100644 ---- /dev/null (date 1709903119912) -+++ b/app/src/main/res/layout/page_nested_list.xml (date 1709903119912) -@@ -0,0 +1,13 @@ -+ -+ -+ -+ -+ -\ No newline at end of file -Index: gradle/wrapper/gradle-wrapper.properties -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>#Fri Sep 04 18:15:43 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.0-all.zip\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>ISO-8859-1 -=================================================================== -diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties ---- a/gradle/wrapper/gradle-wrapper.properties (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/gradle/wrapper/gradle-wrapper.properties (date 1709880931213) -@@ -3,4 +3,4 @@ - distributionPath=wrapper/dists - zipStoreBase=GRADLE_USER_HOME - zipStorePath=wrapper/dists --distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip -+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip -Index: app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.book\n\nimport android.annotation.SuppressLint\nimport android.content.Context.MODE_PRIVATE\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.widget.Toast\nimport androidx.navigation.fragment.findNavController\nimport com.google.gson.Gson\nimport kotlinx.android.synthetic.main.app_bar_main.*\nimport kotlinx.android.synthetic.main.fragment_book.*\nimport kotlinx.android.synthetic.main.line_bookinfo_text.*\nimport kotlinx.android.synthetic.main.line_booktandb.*\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.json.VolumeStructure\nimport top.fumiama.copymanga.manga.Reader\nimport top.fumiama.copymanga.template.general.NoBackRefreshFragment\nimport top.fumiama.copymanga.tools.ui.Navigate\nimport top.fumiama.copymanga.ui.comicdl.ComicDlFragment\nimport top.fumiama.dmzj.copymanga.R\nimport java.io.File\nimport java.lang.Thread.sleep\nimport java.lang.ref.WeakReference\n\nclass BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {\n var isOnPause = false\n private var mBookHandler: BookHandler? = null\n\n override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n super.onViewCreated(view, savedInstanceState)\n\n ComicDlFragment.exit = false\n fbl?.setPadding(0, 0, 0, navBarHeight)\n\n if(isFirstInflate) {\n var path = \"\"\n arguments?.apply {\n if (getBoolean(\"loadJson\")) {\n getString(\"name\")?.let { name ->\n mainWeakReference?.get()?.getExternalFilesDir(\"\")?.let {\n Gson().fromJson(File(File(it, name), \"info.json\").readText(), Array::class.java)\n }?.apply {\n if (isEmpty() || get(0).results.list.isEmpty()) {\n findNavController().popBackStack()\n return\n }\n else {\n path = get(0).results.list[0].comic_path_word\n }\n }\n }\n } else getString(\"path\").let {\n if (it != null) path = it\n else {\n findNavController().popBackStack()\n return\n }\n }\n }\n mBookHandler = BookHandler(WeakReference(this), path)\n Log.d(\"MyBF\", \"read path: $path\")\n bookHandler = mBookHandler\n Thread {\n sleep(600)\n mBookHandler?.startLoad()\n }.start()\n } else {\n bookHandler = mBookHandler\n }\n }\n\n override fun onResume() {\n super.onResume()\n isOnPause = false\n bookHandler = mBookHandler\n mainWeakReference?.get()?.apply {\n toolbar.title = mBookHandler?.book?.results?.comic?.name\n }\n setStartRead()\n }\n\n override fun onPause() {\n super.onPause()\n isOnPause = true\n }\n\n override fun onDestroy() {\n super.onDestroy()\n mBookHandler?.destroy()\n mBookHandler?.ads?.forEach {\n it.exit = true\n }\n bookHandler = null\n }\n\n fun setStartRead() {\n if(mBookHandler?.chapterNames?.isNotEmpty() == true) mainWeakReference?.get()?.apply {\n mBookHandler?.book?.results?.comic?.let { comic ->\n getPreferences(MODE_PRIVATE).getInt(comic.name, -1).let { p ->\n this@BookFragment.lbbstart.apply {\n var i = 0\n if(p >= 0) {\n text = mBookHandler!!.chapterNames[p]\n i = p\n }\n setOnClickListener {\n mBookHandler?.urlArray?.let {\n Reader.viewMangaAt(comic.name, i, it)\n }\n }\n }\n }\n }\n }\n }\n\n @SuppressLint(\"SetTextI18n\")\n fun setAddToShelf() {\n if(mBookHandler?.chapterNames?.isNotEmpty() == true) {\n val b = MainActivity.shelf?.query(mBookHandler?.path!!)\n mBookHandler?.collect = b?.results?.collect?:-2\n Log.d(\"MyBF\", \"get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}\")\n b?.results?.browse?.chapter_name?.let { name ->\n btsub.text = \"${btsub.text} ${getString(R.string.text_format_cloud_read_to).format(name)}\"\n }\n mBookHandler?.collect?.let { collect ->\n if (collect > 0) {\n this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)\n }\n }\n mBookHandler?.book?.results?.comic?.let { comic ->\n this@BookFragment.lbbsub.setOnClickListener {\n if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) {\n mBookHandler?.collect?.let { collect ->\n if (collect < 0) return@setOnClickListener\n Thread{\n val re = MainActivity.shelf?.del(collect)\n activity?.runOnUiThread {\n Toast.makeText(context, re, Toast.LENGTH_SHORT).show()\n if (re == \"请求成功\") {\n this@BookFragment.lbbsub.setText(R.string.button_sub)\n }\n }\n }.start()\n }\n return@setOnClickListener\n }\n Thread{\n val re = MainActivity.shelf?.add(comic.uuid)\n activity?.runOnUiThread {\n Toast.makeText(context, re, Toast.LENGTH_SHORT).show()\n if (re == \"修改成功\") {\n this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)\n }\n }\n }.start()\n }\n }\n }\n }\n\n fun navigate2dl(){\n val bundle = Bundle()\n bundle.putString(\"path\", arguments?.getString(\"path\")?:\"null\")\n bundle.putString(\"name\", mBookHandler!!.book?.results?.comic?.name)\n if(mBookHandler!!.vols != null) {\n bundle.putBoolean(\"loadJson\", true)\n }\n bundle.putStringArray(\"group\", mBookHandler!!.gpws)\n bundle.putStringArray(\"groupNames\", mBookHandler!!.keys)\n bundle.putIntArray(\"count\", mBookHandler!!.cnts)\n findNavController().let {\n Navigate.safeNavigateTo(it, R.id.action_nav_book_to_nav_group, bundle)\n }\n }\n\n companion object {\n var bookHandler: BookHandler? = null\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -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 ---- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt (date 1709903835366) -@@ -6,14 +6,18 @@ - 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 - 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.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.json.VolumeStructure - import top.fumiama.copymanga.manga.Reader - import top.fumiama.copymanga.template.general.NoBackRefreshFragment -@@ -32,14 +36,14 @@ - super.onViewCreated(view, savedInstanceState) - - ComicDlFragment.exit = false -- fbl?.setPadding(0, 0, 0, navBarHeight) -+ fbvp?.setPadding(0, 0, 0, navBarHeight) - - if(isFirstInflate) { - var path = "" - arguments?.apply { - if (getBoolean("loadJson")) { - getString("name")?.let { name -> -- mainWeakReference?.get()?.getExternalFilesDir("")?.let { -+ activity?.getExternalFilesDir("")?.let { - Gson().fromJson(File(File(it, name), "info.json").readText(), Array::class.java) - }?.apply { - if (isEmpty() || get(0).results.list.isEmpty()) { -@@ -62,10 +66,12 @@ - mBookHandler = BookHandler(WeakReference(this), path) - Log.d("MyBF", "read path: $path") - bookHandler = mBookHandler -- Thread { -- sleep(600) -- mBookHandler?.startLoad() -- }.start() -+ lifecycleScope.launch { -+ withContext(Dispatchers.IO) { -+ sleep(600) -+ mBookHandler?.startLoad() -+ } -+ } - } else { - bookHandler = mBookHandler - } -@@ -75,7 +81,7 @@ - super.onResume() - isOnPause = false - bookHandler = mBookHandler -- mainWeakReference?.get()?.apply { -+ activity?.apply { - toolbar.title = mBookHandler?.book?.results?.comic?.name - } - setStartRead() -@@ -96,7 +102,7 @@ - } - - fun setStartRead() { -- if(mBookHandler?.chapterNames?.isNotEmpty() == true) mainWeakReference?.get()?.apply { -+ if(mBookHandler?.chapterNames?.isNotEmpty() == true) activity?.apply { - mBookHandler?.book?.results?.comic?.let { comic -> - getPreferences(MODE_PRIVATE).getInt(comic.name, -1).let { p -> - this@BookFragment.lbbstart.apply { -@@ -118,12 +124,13 @@ - - @SuppressLint("SetTextI18n") - fun setAddToShelf() { -- if(mBookHandler?.chapterNames?.isNotEmpty() == true) { -+ if(mBookHandler?.chapterNames?.isNotEmpty() != true) return -+ lifecycleScope.launch { - val b = MainActivity.shelf?.query(mBookHandler?.path!!) - mBookHandler?.collect = b?.results?.collect?:-2 - Log.d("MyBF", "get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}") -- b?.results?.browse?.chapter_name?.let { name -> -- btsub.text = "${btsub.text} ${getString(R.string.text_format_cloud_read_to).format(name)}" -+ tic.text = b?.results?.browse?.chapter_name?.let { name -> -+ getString(R.string.text_format_cloud_read_to).format(name) - } - mBookHandler?.collect?.let { collect -> - if (collect > 0) { -@@ -132,30 +139,24 @@ - } - mBookHandler?.book?.results?.comic?.let { comic -> - this@BookFragment.lbbsub.setOnClickListener { -- if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) { -- mBookHandler?.collect?.let { collect -> -- if (collect < 0) return@setOnClickListener -- Thread{ -+ lifecycleScope.launch clickLaunch@ { -+ if (this@BookFragment.lbbsub.text != getString(R.string.button_sub)) { -+ mBookHandler?.collect?.let { collect -> -+ if (collect < 0) return@clickLaunch - val re = MainActivity.shelf?.del(collect) -- activity?.runOnUiThread { -- Toast.makeText(context, re, Toast.LENGTH_SHORT).show() -- if (re == "请求成功") { -- this@BookFragment.lbbsub.setText(R.string.button_sub) -- } -- } -- }.start() -+ Toast.makeText(context, re, Toast.LENGTH_SHORT).show() -+ if (re == "请求成功") { -+ this@BookFragment.lbbsub.setText(R.string.button_sub) -+ } -+ } -+ return@clickLaunch - } -- return@setOnClickListener -- } -- Thread{ - val re = MainActivity.shelf?.add(comic.uuid) -- activity?.runOnUiThread { -- Toast.makeText(context, re, Toast.LENGTH_SHORT).show() -- if (re == "修改成功") { -- this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed) -- } -- } -- }.start() -+ Toast.makeText(context, re, Toast.LENGTH_SHORT).show() -+ if (re == "修改成功") { -+ this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed) -+ } -+ } - } - } - } -Index: app/src/main/java/top/fumiama/copymanga/update/SimpleKanban.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.update\n\nimport android.util.Log\n\nclass SimpleKanban(private val client: Client, private val pwd: String) { //must run in thread\n private val raw: ByteArray?\n get() {\n var times = 3\n var re: ByteArray\n var firstRecv: ByteArray\n do {\n re = byteArrayOf()\n if(client.initConnect()) {\n client.sendMessage(\"${pwd}catquit\")\n client.receiveRawMessage(33) //Welcome to simple kanban server.\n try {\n firstRecv = client.receiveRawMessage(4) //le\n val length = convert2Int(firstRecv)\n Log.d(\"MySK\", \"Msg len: $length\")\n if(firstRecv.size > 4) re += firstRecv.copyOfRange(4, firstRecv.size)\n re += client.receiveRawMessage(length - re.size, setProgress = true)\n break\n } catch (e: Exception) {\n e.printStackTrace()\n }\n client.closeConnect()\n }\n } while (times-- > 0)\n return if(re.isEmpty()) null else re\n }\n\n private fun convert2Int(buffer: ByteArray) =\n (buffer[3].toInt() and 0xff shl 24) or\n (buffer[2].toInt() and 0xff shl 16) or\n (buffer[1].toInt() and 0xff shl 8) or\n (buffer[0].toInt() and 0xff)\n\n fun fetchRaw(doOnLoadFailure: ()->Unit = {\n Log.d(\"MySD\", \"Fetch dict failed\")\n }, doOnLoadSuccess: (data: ByteArray)->Unit = {\n Log.d(\"MySD\", \"Fetch dict success\")\n }) {\n raw?.apply {\n doOnLoadSuccess(this)\n }?:doOnLoadFailure()\n }\n\n operator fun get(version: Int): String =\n if(client.initConnect()) {\n client.sendMessage(\"${pwd}get${version}quit\")\n client.receiveRawMessage(36) //Welcome to simple kanban server. get\n val r = try {\n val firstRecv = client.receiveRawMessage(4)\n if(firstRecv.decodeToString() == \"null\") \"null\"\n else {\n val length = convert2Int(firstRecv)\n Log.d(\"MySK\", \"Msg len: $length\")\n var re = byteArrayOf()\n if(firstRecv.size > 4) re += firstRecv.copyOfRange(4, firstRecv.size)\n re += client.receiveRawMessage(length - re.size)\n if(re.isNotEmpty()) re.decodeToString() else \"null\"\n }\n } catch (e: Exception){\n e.printStackTrace()\n \"null\"\n }\n client.closeConnect()\n r\n } else \"null\"\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/update/SimpleKanban.kt b/app/src/main/java/top/fumiama/copymanga/update/SimpleKanban.kt ---- a/app/src/main/java/top/fumiama/copymanga/update/SimpleKanban.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/update/SimpleKanban.kt (date 1709886316131) -@@ -7,17 +7,17 @@ - get() { - var times = 3 - var re: ByteArray -- var firstRecv: ByteArray -+ var firstReceived: ByteArray - do { - re = byteArrayOf() - if(client.initConnect()) { - client.sendMessage("${pwd}catquit") - client.receiveRawMessage(33) //Welcome to simple kanban server. - try { -- firstRecv = client.receiveRawMessage(4) //le -- val length = convert2Int(firstRecv) -+ firstReceived = client.receiveRawMessage(4) //le -+ val length = convert2Int(firstReceived) - Log.d("MySK", "Msg len: $length") -- if(firstRecv.size > 4) re += firstRecv.copyOfRange(4, firstRecv.size) -+ if(firstReceived.size > 4) re += firstReceived.copyOfRange(4, firstReceived.size) - re += client.receiveRawMessage(length - re.size, setProgress = true) - break - } catch (e: Exception) { -@@ -35,9 +35,9 @@ - (buffer[1].toInt() and 0xff shl 8) or - (buffer[0].toInt() and 0xff) - -- fun fetchRaw(doOnLoadFailure: ()->Unit = { -+ suspend fun fetchRaw(doOnLoadFailure: suspend ()->Unit = { - Log.d("MySD", "Fetch dict failed") -- }, doOnLoadSuccess: (data: ByteArray)->Unit = { -+ }, doOnLoadSuccess: suspend (data: ByteArray)->Unit = { - Log.d("MySD", "Fetch dict success") - }) { - raw?.apply { -Index: .idea/gradle.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>\n\n \n \n \n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/.idea/gradle.xml b/.idea/gradle.xml ---- a/.idea/gradle.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/.idea/gradle.xml (date 1709880886968) -@@ -4,10 +4,8 @@ - - \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n \n\n \n \n \n \n \n\n \n \n\n \n \n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml ---- a/app/src/main/res/navigation/mobile_navigation.xml (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/res/navigation/mobile_navigation.xml (date 1709906072716) -@@ -224,7 +224,7 @@ - - - UTF-8 -=================================================================== -diff --git a/app/src/main/res/drawable-anydpi/ic_hot.xml b/app/src/main/res/drawable-anydpi/ic_hot.xml -new file mode 100644 ---- /dev/null (date 1709889333999) -+++ b/app/src/main/res/drawable-anydpi/ic_hot.xml (date 1709889333999) -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.rank\n\nimport android.os.Bundle\nimport com.google.android.material.tabs.TabLayout\nimport kotlinx.android.synthetic.main.fragment_rank.*\nimport kotlinx.android.synthetic.main.line_rank.view.*\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.template.ui.InfoCardLoader\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.copymanga.tools.ui.UITools\nimport top.fumiama.dmzj.copymanga.R\nimport java.lang.Thread.sleep\nimport java.lang.ref.WeakReference\n\n@ExperimentalStdlibApi\nclass RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, true) {\n private val sortWay = listOf(\"day\", \"week\", \"month\", \"total\")\n private var sortValue = 0\n private val audienceWay = listOf(\"\", \"male\", \"female\")\n private var audience = 0 // 0 all 1 male 2 female\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n wr = WeakReference(this)\n }\n\n override fun onPause() {\n super.onPause()\n ad?.exit = true\n }\n\n override fun onResume() {\n super.onResume()\n ad?.exit = true\n }\n\n override fun onDestroy() {\n super.onDestroy()\n wr = null\n ad?.exit = true\n }\n\n override fun getApiUrl() =\n getString(R.string.rankApiUrl).format(\n CMApi.myHostApiUrl,\n page * 21,\n sortWay[sortValue],\n audienceWay[audience]\n )\n\n override fun setListeners() {\n super.setListeners()\n frlai.lrt.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener {\n override fun onTabReselected(tab: TabLayout.Tab?) {}\n\n override fun onTabSelected(tab: TabLayout.Tab?) {\n setSortValue(tab?.position?:0)\n }\n\n override fun onTabUnselected(tab: TabLayout.Tab?) {}\n })\n }\n\n private fun setSortValue(value: Int) {\n sortValue = value\n Thread{\n sleep(400)\n if(ad?.exit != true) activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n\n fun showSexInfo(toolsBox: UITools) {\n if (ad?.exit != false) return\n toolsBox.buildInfo(\"切换类型\", \"选择一种想筛选的漫画类型\",\n \"男频\", \"全部\", \"女频\", {\n audience = 1\n reset()\n Thread {\n sleep(600)\n addPage()\n }.start()\n }, {\n audience = 0\n reset()\n Thread {\n sleep(600)\n addPage()\n }.start()\n }, {\n audience = 2\n reset()\n Thread {\n sleep(600)\n addPage()\n }.start()\n })\n }\n\n companion object {\n var wr: WeakReference? = null\n }\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt (date 1709908862385) -@@ -13,7 +13,7 @@ - import java.lang.ref.WeakReference - - @ExperimentalStdlibApi --class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, true) { -+class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank_to_nav_book, isTypeBook = true) { - private val sortWay = listOf("day", "week", "month", "total") - private var sortValue = 0 - private val audienceWay = listOf("", "male", "female") -Index: app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.template.ui\n\nimport android.annotation.SuppressLint\nimport android.net.Uri\nimport android.util.Log\nimport android.view.View\nimport androidx.fragment.app.Fragment\nimport com.bumptech.glide.Glide\nimport com.bumptech.glide.load.model.GlideUrl\nimport kotlinx.android.synthetic.main.card_book.*\nimport kotlinx.android.synthetic.main.card_book.view.*\nimport kotlinx.android.synthetic.main.line_horizonal_empty.view.*\nimport kotlinx.android.synthetic.main.line_lazybooklines.*\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener\nimport top.fumiama.dmzj.copymanga.R\nimport java.io.File\nimport java.lang.ref.WeakReference\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass CardList(\n private val fragment: WeakReference,\n private val cardWidth: Int,\n private val cardHeight: Int,\n private val cardPerRow: Int\n) {\n private val that get() = fragment.get()\n private var rows:Array = arrayOfNulls(20)\n private var index = 0\n private var count = 0\n private var cardLoadingWaits = AtomicInteger()\n var initClickListeners: InitClickListeners? = null\n var exitCardList = false\n\n fun reset(){\n rows = arrayOfNulls(20)\n index = 0\n count = 0\n exitCardList = false\n }\n\n private fun manageRow() {\n if(!exitCardList && count++ % cardPerRow == 0) inflateRow()\n Log.d(\"MyCL\", \"index: $index, cardPR: $cardPerRow\")\n }\n\n private fun inflateRow(){\n that?.apply {\n layoutInflater.inflate(R.layout.line_horizonal_empty, mydll, false)?.let {\n if(exitCardList) return\n it.layoutParams.height = cardHeight + 16\n activity?.runOnUiThread {\n if(exitCardList) return@runOnUiThread\n mydll?.addView(it)\n }\n recycleOneRow(it)\n index++\n }\n }\n }\n private fun recycleOneRow(v:View?){\n val relativeIndex = index % 20\n if(rows[relativeIndex] == null) rows[relativeIndex] = v\n else {\n val victim = rows[relativeIndex]\n that?.apply {\n activity?.runOnUiThread {\n if(exitCardList) return@runOnUiThread\n mydll?.removeView(victim)\n mys?.scrollY = mys?.scrollY?.minus(cardHeight + 16)?:0\n }\n }\n rows[relativeIndex] = v\n }\n }\n\n @ExperimentalStdlibApi\n fun addCard(name: String, append: String? = null, head: String? = null, path: String? = null, chapterUUID: String? = null, pn: Int? = null, isFinish: Boolean = false, isNew: Boolean = false) {\n if (exitCardList) return\n manageRow()\n that?.apply {\n layoutInflater.inflate(R.layout.card_book, mydll?.ltbtn, false)?.let {\n val card = it.cic\n card.name = name\n card.append = append\n card.headImageUrl = head\n card.path = path\n card.index = index - 1\n card.chapterUUID = chapterUUID\n card.pageNumber = pn\n card.isFinish = isFinish\n card.isNew = isNew\n activity?.runOnUiThread {\n if (exitCardList) return@runOnUiThread\n addCard(it)\n }\n }\n }\n }\n\n @SuppressLint(\"SetTextI18n\")\n @ExperimentalStdlibApi\n fun addCard(cardFrame: View) {\n val card = cardFrame.cic\n if (card.index < 0) return\n val name = card.name + (card.append?:\"\")\n val head = card.headImageUrl\n val file = File(that?.context?.getExternalFilesDir(\"\"), card.name)\n if(exitCardList) return\n cardFrame.let {\n it.tic.text = name\n if(!file.exists()){\n if(head != null) {\n that?.context?.let { context ->\n val waitMillis = cardLoadingWaits.getAndIncrement().toLong()*200\n val g = Glide.with(context).load(\n GlideUrl(CMApi.proxy?.wrap(head)?:head, CMApi.myGlideHeaders)\n ).addListener(GlideHideLottieViewListener(WeakReference(it.laic)) {\n if (exitCardList) return@GlideHideLottieViewListener\n cardLoadingWaits.decrementAndGet()\n })\n if (waitMillis > 0) it.imic.postDelayed({\n if (exitCardList) return@postDelayed\n g.into(it.imic)\n }, waitMillis) else g.into(it.imic)\n }\n } else {\n it.laic.pauseAnimation()\n it.laic.visibility = View.GONE\n it.imic.setImageResource(R.drawable.img_defmask)\n }\n } else {\n val img = File(file, \"head.jpg\")\n it.laic.pauseAnimation()\n it.laic.visibility = View.GONE\n if(img.exists()) {\n it.imic.setImageURI(Uri.fromFile(img))\n } else {\n it.imic.setImageResource(R.drawable.img_defmask)\n }\n }\n if(card.isFinish) it.sgnic.visibility = View.VISIBLE\n if(card.isNew) it.sgnnew.visibility = View.VISIBLE\n initClickListeners?.prepareListeners(card, card.name, card.path, card.chapterUUID, card.pageNumber)\n rows[card.index % 20]?.ltbtn?.addView(it)\n it.layoutParams?.height = cardHeight\n it.layoutParams?.width = cardWidth\n }\n }\n interface InitClickListeners{\n fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?)\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt ---- a/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt (date 1709908106372) -@@ -36,6 +36,7 @@ - rows = arrayOfNulls(20) - index = 0 - count = 0 -+ cardLoadingWaits.set(0) - exitCardList = false - } - -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.sort\n\nimport android.animation.ObjectAnimator\nimport com.github.zawadz88.materialpopupmenu.popupMenu\nimport com.google.gson.Gson\nimport kotlinx.android.synthetic.main.anchor_popular.view.*\nimport kotlinx.android.synthetic.main.line_sort.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.json.FilterStructure\nimport top.fumiama.copymanga.template.http.AutoDownloadThread\nimport top.fumiama.copymanga.template.ui.InfoCardLoader\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.dmzj.copymanga.R\nimport java.lang.Thread.sleep\n\n@ExperimentalStdlibApi\nclass SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort_to_nav_book) {\n private val sortWay = listOf(\"-datetime_updated\", \"datetime_updated\", \"-popular\", \"popular\")\n private var theme = -1\n private var region = -1\n private var sortValue = 0\n private var filter: FilterStructure? = null\n\n override fun getApiUrl() =\n getString(R.string.sortApiUrl).format(\n CMApi.myHostApiUrl,\n page * 21,\n sortWay[sortValue],\n if(theme >= 0) (filter?.results?.theme?.get(theme)?.path_word ?: \"\") else \"\",\n if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: \"\") else \"\",\n )\n\n override fun setListeners() {\n super.setListeners()\n setUpdate()\n setHot()\n AutoDownloadThread(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) {\n if(ad?.exit == true) return@AutoDownloadThread\n it?.let {\n filter = Gson().fromJson(it.inputStream().reader(), FilterStructure::class.java)\n if(ad?.exit == true) return@AutoDownloadThread\n activity?.runOnUiThread{\n if(ad?.exit != true) setClasses()\n }\n }\n }.start()\n }\n\n private fun setUpdate(){\n if(ad?.exit == true) return\n line_sort_time.apt.setText(R.string.menu_update_time)\n line_sort_time.setOnClickListener {\n sortValue = if(it.apim.rotation == 0f) {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 1\n }else{\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 0\n }\n Thread{\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n\n private fun setClasses(){\n filter?.results?.top?.let { items ->\n if(ad?.exit == true) return@let\n line_sort_region.apt.text = \"全部\"\n line_sort_region.setOnClickListener {\n val popupMenu = popupMenu {\n style = R.style.Widget_MPM_Menu_Dark_CustomBackground\n section {\n item {\n label = \"全部\"\n labelColor = it.apt.currentTextColor\n callback = {\n region = -1\n it.apt.text = \"全部\"\n Thread{\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n for(i in items.indices) item {\n label = items[i].name\n labelColor = it.apt.currentTextColor\n callback = { //optional\n it.apt.text = label\n region = i\n Thread{\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n }\n }\n this.context?.let { it1 -> popupMenu.show(it1, it) }\n }\n }\n filter?.results?.theme?.let { items ->\n if(ad?.exit == true) return@let\n line_sort_class.apt.text = \"全部\"\n line_sort_class.setOnClickListener {\n val popupMenu = popupMenu {\n style = R.style.Widget_MPM_Menu_Dark_CustomBackground\n section {\n item {\n label = \"全部\"\n labelColor = it.apt.currentTextColor\n callback = {\n theme = -1\n it.apt.text = \"全部\"\n Thread{\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n for(i in items.indices) item {\n label = items[i].name\n labelColor = it.apt.currentTextColor\n callback = { //optional\n it.apt.text = label\n theme = i\n Thread{\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n }\n }\n this.context?.let { it1 -> popupMenu.show(it1, it) }\n }\n }\n }\n\n private fun setHot() {\n if(ad?.exit == true) return\n line_sort_hot.apt.setText(R.string.menu_hot)\n line_sort_hot.setOnClickListener {\n sortValue = if (it.apim.rotation == 0f) {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 3\n } else {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 2\n }\n Thread {\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt (date 1709908962128) -@@ -1,24 +1,22 @@ - package top.fumiama.copymanga.ui.cardflow.sort - --import android.animation.ObjectAnimator -+import android.os.Bundle -+import android.view.View - import com.github.zawadz88.materialpopupmenu.popupMenu - import com.google.gson.Gson - import kotlinx.android.synthetic.main.anchor_popular.view.* - import kotlinx.android.synthetic.main.line_sort.* --import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.json.FilterStructure - import top.fumiama.copymanga.template.http.AutoDownloadThread --import top.fumiama.copymanga.template.ui.InfoCardLoader -+import top.fumiama.copymanga.template.ui.StatusCardFlow - import top.fumiama.copymanga.tools.api.CMApi - import top.fumiama.dmzj.copymanga.R - import java.lang.Thread.sleep - - @ExperimentalStdlibApi --class SortFragment : InfoCardLoader(R.layout.fragment_sort, R.id.action_nav_sort_to_nav_book) { -- private val sortWay = listOf("-datetime_updated", "datetime_updated", "-popular", "popular") -+class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layout.fragment_sort) { - private var theme = -1 - private var region = -1 -- private var sortValue = 0 - private var filter: FilterStructure? = null - - override fun getApiUrl() = -@@ -30,10 +28,14 @@ - if(region >= 0) (filter?.results?.top?.get(region)?.path_word ?: "") else "", - ) - -+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { -+ super.onViewCreated(view, savedInstanceState) -+ lineUpdate = line_sort_time -+ lineHot = line_sort_hot -+ } -+ - override fun setListeners() { - super.setListeners() -- setUpdate() -- setHot() - AutoDownloadThread(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) { - if(ad?.exit == true) return@AutoDownloadThread - it?.let { -@@ -45,27 +47,6 @@ - } - }.start() - } -- -- private fun setUpdate(){ -- if(ad?.exit == true) return -- line_sort_time.apt.setText(R.string.menu_update_time) -- line_sort_time.setOnClickListener { -- sortValue = if(it.apim.rotation == 0f) { -- ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() -- 1 -- }else{ -- ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() -- 0 -- } -- Thread{ -- sleep(400) -- activity?.runOnUiThread { -- reset() -- addPage() -- } -- }.start() -- } -- } - - private fun setClasses(){ - filter?.results?.top?.let { items -> -@@ -153,25 +134,4 @@ - } - } - } -- -- private fun setHot() { -- if(ad?.exit == true) return -- line_sort_hot.apt.setText(R.string.menu_hot) -- line_sort_hot.setOnClickListener { -- sortValue = if (it.apim.rotation == 0f) { -- ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() -- 3 -- } else { -- ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() -- 2 -- } -- Thread { -- sleep(400) -- activity?.runOnUiThread { -- reset() -- addPage() -- } -- }.start() -- } -- } - } -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/template/ui/ThemeCardFlow.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.template.ui\n\nimport android.os.Bundle\nimport kotlinx.android.synthetic.main.app_bar_main.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.tools.api.CMApi\n\n@ExperimentalStdlibApi\nopen class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav) {\n private var theme = \"\"\n override fun getApiUrl() =\n getString(api).format(\n CMApi.myHostApiUrl,\n page * 21,\n sortWay[sortValue],\n theme\n )\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n arguments?.apply {\n getString(\"path\")?.apply { theme = this }\n getString(\"name\")?.apply {\n mainWeakReference?.get()?.toolbar?.title = this\n }\n }\n }\n\n override fun onResume() {\n super.onResume()\n arguments?.getString(\"name\")?.apply {\n mainWeakReference?.get()?.toolbar?.title = this\n }\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/ThemeCardFlow.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/ThemeCardFlow.kt ---- a/app/src/main/java/top/fumiama/copymanga/template/ui/ThemeCardFlow.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/ThemeCardFlow.kt (date 1709907861458) -@@ -1,12 +1,17 @@ - package top.fumiama.copymanga.template.ui - - import android.os.Bundle -+import android.view.LayoutInflater -+import android.view.View -+import android.view.ViewGroup - import kotlinx.android.synthetic.main.app_bar_main.* -+import kotlinx.android.synthetic.main.line_finish.* - import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.tools.api.CMApi -+import top.fumiama.dmzj.copymanga.R - - @ExperimentalStdlibApi --open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav) { -+open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav, R.layout.fragment_statuscardflow) { - private var theme = "" - override fun getApiUrl() = - getString(api).format( -@@ -26,6 +31,12 @@ - } - } - -+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { -+ super.onViewCreated(view, savedInstanceState) -+ lineUpdate = line_finish_time -+ lineHot = line_finish_pop -+ } -+ - override fun onResume() { - super.onResume() - arguments?.getString("name")?.apply { -Index: app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.tools.api\n\nimport android.util.Base64\nimport androidx.preference.PreferenceManager\nimport com.bumptech.glide.load.model.LazyHeaders\nimport top.fumiama.dmzj.copymanga.R\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.tools.http.DownloadTools\nimport top.fumiama.copymanga.tools.http.Proxy\nimport top.fumiama.copymanga.tools.http.Resolution\nimport java.io.File\nimport java.net.URLEncoder\n\nobject CMApi {\n var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null\n var resolution = Resolution(Regex(\"\\\\.c\\\\d+x\\\\.\"))\n var myGlideHeaders: LazyHeaders? = null\n get() {\n MainActivity.mainWeakReference?.get()?.let {\n PreferenceManager.getDefaultSharedPreferences(it).apply {\n if(field === null)\n field = LazyHeaders.Builder()\n .addHeader(\"referer\", MainActivity.mainWeakReference?.get()?.getString(R.string.referer)!!)\n .addHeader(\"User-Agent\", MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)!!)\n .addHeader(\"source\", \"copyApp\")\n .addHeader(\"webp\", \"1\")\n .addHeader(\"version\", MainActivity.mainWeakReference?.get()?.getString(R.string.app_ver)!!)\n .addHeader(\"region\", if(!getBoolean(\"settings_cat_net\", false)) \"1\" else \"0\")\n .addHeader(\"platform\", \"3\")\n .build()\n }\n }\n return field\n }\n var myHostApiUrl: String = \"\"\n get() {\n if(field != \"\") return field\n MainActivity.mainWeakReference?.get()?.let {\n PreferenceManager.getDefaultSharedPreferences(it).apply {\n getString(\"settings_cat_net_et_api_url\", \"\")?.let { host ->\n if(host != \"\") {\n field = host\n return host\n }\n }\n }\n field = it.getString(R.string.hostUrl)\n }\n return field\n }\n\n fun getZipFile(exDir: File?, manga: String, caption: CharSequence, name: CharSequence) = File(exDir, \"$manga/$caption/$name.zip\")\n fun getChapterInfoApiUrl(arg1: String?, arg2: String?) =\n MainActivity.mainWeakReference?.get()?.getString(R.string.chapterInfoApiUrl)?.format(myHostApiUrl, arg1, arg2)\n fun getGroupInfoApiUrl(arg1: String?, arg2: String?, arg3: Int? = 0) =\n MainActivity.mainWeakReference?.get()?.getString(R.string.groupInfoApiUrl)?.format(myHostApiUrl, arg1, arg2, arg3)\n fun getLoginConnection(username: String, pwd: String, salt: Int) =\n MainActivity.mainWeakReference?.get()?.getString(R.string.loginApiUrl)?.format(myHostApiUrl)?.let {\n DownloadTools.getConnection(it, \"POST\")?.apply {\n MainActivity.mainWeakReference?.get()?.let {\n PreferenceManager.getDefaultSharedPreferences(it).apply {\n doOutput = true\n setRequestProperty(\"content-type\", \"application/x-www-form-urlencoded;charset=utf-8\")\n setRequestProperty(\"platform\", \"3\")\n setRequestProperty(\"accept\", \"application/json\")\n val r = if(!getBoolean(\"settings_cat_net_sw_use_foreign\", false)) \"1\" else \"0\"\n val pwdb64 = Base64.encode(\"$pwd-$salt\".toByteArray(), Base64.DEFAULT).decodeToString()\n outputStream.write(\"username=${URLEncoder.encode(username)}&password=$pwdb64&salt=$salt&platform=3&authorization=Token+&version=1.4.4&source=copyApp®ion=$r&webp=1\".toByteArray())\n }\n }\n }\n }\n }\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt b/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt ---- a/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt (date 1709890277655) -@@ -13,7 +13,7 @@ - - object CMApi { - var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null -- var resolution = Resolution(Regex("\\.c\\d+x\\.")) -+ var resolution = Resolution(Regex("c\\d+x\\.")) - var myGlideHeaders: LazyHeaders? = null - get() { - MainActivity.mainWeakReference?.get()?.let { -Index: app/build.gradle -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n defaultConfig {\n compileSdk 34\n applicationId 'top.fumiama.copymanga'\n minSdkVersion 23\n targetSdkVersion 34\n versionCode 45\n versionName '2.1.2'\n resConfigs 'zh', 'zh-rCN'\n\n testInstrumentationRunner \"androidx.test.runner.AndroidJUnitRunner\"\n }\n\n aaptOptions {\n cruncherEnabled = false\n }\n\n buildTypes {\n release {\n minifyEnabled true\n shrinkResources true\n proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n }\n /*winrelease {\n minifyEnabled true\n shrinkResources true\n proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n }\n debug{\n minifyEnabled true\n shrinkResources true\n proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'\n }*/\n }\n compileOptions {\n sourceCompatibility JavaVersion.VERSION_11\n targetCompatibility JavaVersion.VERSION_11\n }\n kotlinOptions {\n jvmTarget = '11'\n }\n bundle{\n density{\n enableSplit = true\n }\n language{\n enableSplit = false\n }\n }\n namespace 'top.fumiama.dmzj.copymanga'\n}\n\ndependencies {\n implementation 'androidx.core:core-ktx:1.12.0'\n implementation 'androidx.appcompat:appcompat:1.6.1'\n implementation 'androidx.legacy:legacy-support-v4:1.0.0'\n implementation 'com.google.android.material:material:1.11.0'\n implementation 'androidx.constraintlayout:constraintlayout:2.1.4'\n implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'\n implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'\n testImplementation 'junit:junit:4.13.2'\n implementation \"androidx.preference:preference-ktx:1.2.1\"\n implementation 'com.afollestad.material-dialogs:input:3.3.0'\n implementation 'com.github.yalantis:ucrop:2.2.6'\n implementation 'com.to.aboomy:pager2banner:1.0.1'\n implementation 'com.github.bumptech.glide:glide:4.14.2'\n annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'\n implementation 'com.google.code.gson:gson:2.10.1'\n implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0'\n implementation 'com.liaoinstan.springview:library:1.7.0'\n implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1'\n implementation 'com.lapism:search:2.4.1@aar'\n implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'\n implementation 'com.airbnb.android:lottie:6.3.0'\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/build.gradle b/app/build.gradle ---- a/app/build.gradle (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/build.gradle (date 1709911026401) -@@ -8,16 +8,13 @@ - applicationId 'top.fumiama.copymanga' - minSdkVersion 23 - targetSdkVersion 34 -- versionCode 45 -- versionName '2.1.2' -- resConfigs 'zh', 'zh-rCN' -+ versionCode 46 -+ versionName '2.1.3' -+ resourceConfigurations += ['zh', 'zh-rCN'] - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - -- aaptOptions { -- cruncherEnabled = false -- } - - buildTypes { - release { -@@ -60,20 +57,20 @@ - implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'com.google.android.material:material:1.11.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' -- implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6' -- implementation 'androidx.navigation:navigation-ui-ktx:2.7.6' -+ implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7' -+ implementation 'androidx.navigation:navigation-ui-ktx:2.7.7' - testImplementation 'junit:junit:4.13.2' - implementation "androidx.preference:preference-ktx:1.2.1" - implementation 'com.afollestad.material-dialogs:input:3.3.0' - implementation 'com.github.yalantis:ucrop:2.2.6' - implementation 'com.to.aboomy:pager2banner:1.0.1' -- implementation 'com.github.bumptech.glide:glide:4.14.2' -- annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2' -+ implementation 'com.github.bumptech.glide:glide:4.16.0' -+ annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0' - implementation 'com.google.code.gson:gson:2.10.1' - implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0' - implementation 'com.liaoinstan.springview:library:1.7.0' - implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1' - implementation 'com.lapism:search:2.4.1@aar' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0' -- implementation 'com.airbnb.android:lottie:6.3.0' -+ implementation 'com.airbnb.android:lottie:6.4.0' - } -Index: app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.template.ui\n\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport androidx.fragment.app.Fragment\nimport androidx.navigation.fragment.findNavController\nimport com.google.gson.Gson\nimport kotlinx.android.synthetic.main.line_lazybooklines.*\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.json.BookListStructure\nimport top.fumiama.copymanga.json.HistoryBookListStructure\nimport top.fumiama.copymanga.json.ShelfStructure\nimport top.fumiama.copymanga.json.TypeBookListStructure\nimport top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate\nimport top.fumiama.copymanga.template.http.AutoDownloadThread\nimport top.fumiama.copymanga.tools.ui.Navigate\nimport java.lang.ref.WeakReference\n\n@ExperimentalStdlibApi\nopen class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isTypeBook: Boolean = false, private val isHistoryBook: Boolean = false, private val isShelfBook: Boolean = false): MangaPagesFragmentTemplate(inflateRes) {\n var offset = 0\n private val subUrl get() = getApiUrl()\n var ad: AutoDownloadThread? = null\n\n override fun addPage(){\n super.addPage()\n ad = AutoDownloadThread(subUrl) {\n if (it == null) {\n activity?.runOnUiThread {\n findNavController().popBackStack()\n }\n return@AutoDownloadThread\n }\n if(isRefresh){\n page = 0\n isRefresh = false\n }\n if(isTypeBook) {\n val bookList = Gson().fromJson(it?.decodeToString(), TypeBookListStructure::class.java)\n bookList?.apply {\n Log.d(\"MyICL\", \"offset:${results.offset}, total:${results.total}\")\n if(results.offset < results.total) {\n if(code == 200) {\n results.list.forEach { book ->\n if(ad?.exit == true) return@AutoDownloadThread\n cardList?.addCard(\n book?.comic?.name?:\"null\", null, book?.comic?.cover,\n book?.comic?.path_word, null, null,\n isFinish = false, isNew = false\n )\n }\n offset += results.list.size\n }\n }\n page++\n }\n } else if(isHistoryBook) {\n val bookList = Gson().fromJson(it?.decodeToString(), HistoryBookListStructure::class.java)\n bookList?.apply {\n Log.d(\"MyICL\", \"offset:${results?.offset}, total:${results?.total}\")\n if(results.offset < results.total) {\n if(code == 200) {\n results?.list?.forEach{ book ->\n if(ad?.exit == true) return@AutoDownloadThread\n cardList?.addCard(\n book?.comic?.name?:\"null\", \"\\n最新${book?.last_chapter_name}\", book?.comic?.cover,\n book?.comic?.path_word, null, null,\n book?.comic?.status==1\n )\n }\n offset += results.list.size\n }\n }\n page++\n }\n } else if (isShelfBook) {\n val bookList = Gson().fromJson(it?.decodeToString(), ShelfStructure::class.java)\n bookList?.apply {\n Log.d(\"MyICL\", \"offset:${results?.offset}, total:${results?.total}\")\n if(results.offset < results.total) {\n if(code == 200) {\n results?.list?.forEach{ book ->\n if(ad?.exit == true) return@AutoDownloadThread\n cardList?.addCard(\n book?.comic?.name?:\"null\", \"\\n读到${book?.last_browse?.last_browse_name}\", book?.comic?.cover,\n book?.comic?.path_word, null, null,\n book?.comic?.status==1,\n book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id\n )\n }\n offset += results.list.size\n }\n }\n page++\n }\n } else {\n val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)\n bookList?.apply {\n Log.d(\"MyICL\", \"offset:${results?.offset}, total:${results?.total}\")\n if(results.offset < results.total) {\n if(code == 200) {\n results?.list?.forEach{ book ->\n if(ad?.exit == true) return@AutoDownloadThread\n cardList?.addCard(book?.name?:\"null\", null, book?.cover, book?.path_word, null, null, false)\n }\n offset += results.list.size\n }\n }\n page++\n }\n }\n onLoadFinish()\n }\n ad?.start()\n }\n override fun initCardList(weakReference: WeakReference) {\n super.initCardList(weakReference)\n cardList = CardList(weakReference, cardWidth, cardHeight, cardPerRow)\n cardList?.initClickListeners = object : CardList.InitClickListeners {\n override fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?) {\n v.setOnClickListener {\n val bundle = Bundle()\n bundle.putString(\"path\", path)\n Navigate.safeNavigateTo(findNavController(), navId, bundle)\n }\n }\n }\n }\n\n open fun getApiUrl(): String{\n return \"\"\n }\n\n override fun onLoadFinish() {\n super.onLoadFinish()\n activity?.runOnUiThread {\n if(ad?.exit != true) mypl.visibility = View.GONE\n }\n }\n\n override fun reset() {\n super.reset()\n offset = 0\n }\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n ad?.exit = false\n }\n\n override fun onResume() {\n super.onResume()\n ad?.exit = false\n }\n\n override fun onDestroy() {\n super.onDestroy()\n ad?.exit = true\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt ---- a/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt (date 1709904313295) -@@ -25,8 +25,8 @@ - - override fun addPage(){ - super.addPage() -- ad = AutoDownloadThread(subUrl) { -- if (it == null) { -+ ad = AutoDownloadThread(subUrl) { data -> -+ if (data == null) { - activity?.runOnUiThread { - findNavController().popBackStack() - } -@@ -37,7 +37,7 @@ - isRefresh = false - } - if(isTypeBook) { -- val bookList = Gson().fromJson(it?.decodeToString(), TypeBookListStructure::class.java) -+ val bookList = Gson().fromJson(data?.decodeToString(), TypeBookListStructure::class.java) - bookList?.apply { - Log.d("MyICL", "offset:${results.offset}, total:${results.total}") - if(results.offset < results.total) { -@@ -56,7 +56,7 @@ - page++ - } - } else if(isHistoryBook) { -- val bookList = Gson().fromJson(it?.decodeToString(), HistoryBookListStructure::class.java) -+ val bookList = Gson().fromJson(data?.decodeToString(), HistoryBookListStructure::class.java) - bookList?.apply { - Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") - if(results.offset < results.total) { -@@ -75,7 +75,7 @@ - page++ - } - } else if (isShelfBook) { -- val bookList = Gson().fromJson(it?.decodeToString(), ShelfStructure::class.java) -+ val bookList = Gson().fromJson(data?.decodeToString(), ShelfStructure::class.java) - bookList?.apply { - Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") - if(results.offset < results.total) { -@@ -83,7 +83,7 @@ - results?.list?.forEach{ book -> - if(ad?.exit == true) return@AutoDownloadThread - cardList?.addCard( -- book?.comic?.name?:"null", "\n读到${book?.last_browse?.last_browse_name}", book?.comic?.cover, -+ book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover, - book?.comic?.path_word, null, null, - book?.comic?.status==1, - book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id -@@ -95,7 +95,7 @@ - page++ - } - } else { -- val bookList = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java) -+ val bookList = Gson().fromJson(data?.decodeToString(), BookListStructure::class.java) - bookList?.apply { - Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") - if(results.offset < results.total) { -Index: app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.template.ui\n\nimport android.animation.ObjectAnimator\nimport android.view.View\nimport kotlinx.android.synthetic.main.anchor_popular.view.*\nimport kotlinx.android.synthetic.main.line_finish.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.dmzj.copymanga.R\n\n@ExperimentalStdlibApi\nopen class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) {\n val sortWay = listOf(\"-datetime_updated\", \"datetime_updated\", \"popular\", \"-popular\")\n var sortValue = 0\n\n override fun getApiUrl() =\n getString(api).format(\n CMApi.myHostApiUrl,\n page * 21,\n sortWay[sortValue]\n )\n\n override fun setListeners() {\n super.setListeners()\n setUpdate(line_finish_time)\n setHot(line_finish_pop)\n }\n\n open fun setUpdate(that: View) {\n that.apply {\n apt.setText(R.string.menu_update_time)\n setOnClickListener {\n sortValue = if(apim.rotation == 0f) {\n ObjectAnimator.ofFloat(apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 1\n }else{\n ObjectAnimator.ofFloat(apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 0\n }\n Thread{\n Thread.sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n }\n\n open fun setHot(that: View) {\n that.apply {\n apt.setText(R.string.menu_hot)\n setOnClickListener {\n sortValue = if (apim.rotation == 0f) {\n ObjectAnimator.ofFloat(apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 3\n } else {\n ObjectAnimator.ofFloat(apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 2\n }\n Thread {\n Thread.sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt ---- a/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt (date 1709908862388) -@@ -3,15 +3,18 @@ - import android.animation.ObjectAnimator - import android.view.View - import kotlinx.android.synthetic.main.anchor_popular.view.* --import kotlinx.android.synthetic.main.line_finish.* --import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference - import top.fumiama.copymanga.tools.api.CMApi - import top.fumiama.dmzj.copymanga.R - - @ExperimentalStdlibApi --open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) { -- val sortWay = listOf("-datetime_updated", "datetime_updated", "popular", "-popular") -+open class StatusCardFlow(private val api: Int, nav: Int, inflateRes: Int, -+ isTypeBook: Boolean = false, -+ isHistoryBook: Boolean = false, -+ isShelfBook: Boolean = false) : InfoCardLoader(inflateRes, nav, isTypeBook, isHistoryBook, isShelfBook) { -+ val sortWay = listOf("-datetime_updated", "datetime_updated", "-popular", "popular") - var sortValue = 0 -+ var lineUpdate: View? = null -+ var lineHot: View? = null - - override fun getApiUrl() = - getString(api).format( -@@ -22,21 +25,17 @@ - - override fun setListeners() { - super.setListeners() -- setUpdate(line_finish_time) -- setHot(line_finish_pop) -+ lineUpdate?.let { setUpdate(it) } -+ lineHot?.let { setHot(it) } -+ lineUpdate?.alpha = 1f -+ lineHot?.alpha = 0.5f - } - - open fun setUpdate(that: View) { - that.apply { - apt.setText(R.string.menu_update_time) - setOnClickListener { -- sortValue = if(apim.rotation == 0f) { -- ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start() -- 1 -- }else{ -- ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start() -- 0 -- } -+ sortValue = triggerLine(false) - Thread{ - Thread.sleep(400) - activity?.runOnUiThread { -@@ -52,13 +51,7 @@ - that.apply { - apt.setText(R.string.menu_hot) - setOnClickListener { -- sortValue = if (apim.rotation == 0f) { -- ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start() -- 3 -- } else { -- ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start() -- 2 -- } -+ sortValue = triggerLine(true) - Thread { - Thread.sleep(400) - activity?.runOnUiThread { -@@ -69,4 +62,46 @@ - } - } - } -+ -+ open fun triggerLine(isHot: Boolean): Int { -+ val hot = lineHot?:return 0 -+ val update = lineUpdate?:return 0 -+ if(sortValue >= 2) { -+ if (isHot) { -+ return if (hot.apim.rotation == 0f) { -+ ObjectAnimator.ofFloat(hot.apim, "rotation", 0f, 180f).setDuration(233).start() -+ 3 -+ } else { -+ ObjectAnimator.ofFloat(hot.apim, "rotation", 180f, 0f).setDuration(233).start() -+ 2 -+ } -+ } else { -+ update.alpha = 1f -+ hot.alpha = 0.5f -+ return if(update.apim.rotation == 0f) { -+ 0 -+ } else { -+ 1 -+ } -+ } -+ } else { -+ if (!isHot) { -+ return if(update.apim.rotation == 0f) { -+ ObjectAnimator.ofFloat(update.apim, "rotation", 0f, 180f).setDuration(233).start() -+ 1 -+ }else{ -+ ObjectAnimator.ofFloat(update.apim, "rotation", 180f, 0f).setDuration(233).start() -+ 0 -+ } -+ } else { -+ hot.alpha = 1f -+ update.alpha = 0.5f -+ return if (hot.apim.rotation == 0f) { -+ 2 -+ } else { -+ 3 -+ } -+ } -+ } -+ } - } -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.shelf\n\nimport android.animation.ObjectAnimator\nimport android.os.Bundle\nimport androidx.navigation.fragment.findNavController\nimport kotlinx.android.synthetic.main.anchor_popular.view.*\nimport kotlinx.android.synthetic.main.line_shelf.*\nimport top.fumiama.copymanga.MainActivity\nimport top.fumiama.copymanga.template.ui.InfoCardLoader\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.dmzj.copymanga.R\nimport java.lang.Thread.sleep\n\n@ExperimentalStdlibApi\nclass ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_sub_to_nav_book, isShelfBook = true) {\n private val sortWay = listOf(\n \"-datetime_updated\",\n \"datetime_updated\",\n \"-datetime_modifier\",\n \"datetime_modifier\",\n \"-datetime_browse\",\n \"datetime_browse\"\n )\n private var sortValue = 0\n\n override fun getApiUrl() =\n getString(R.string.shelfApiUrl).format(\n CMApi.myHostApiUrl,\n page * 21,\n sortWay[sortValue]\n )\n\n override fun onCreate(savedInstanceState: Bundle?) {\n if (MainActivity.member?.hasLogin != true) findNavController().popBackStack()\n super.onCreate(savedInstanceState)\n }\n\n override fun setListeners() {\n super.setListeners()\n setUpdate()\n setModify()\n setBrowse()\n }\n\n private fun setUpdate() {\n if (ad?.exit == true) return\n line_shelf_updated.apt.setText(R.string.menu_update_time)\n line_shelf_updated.setOnClickListener {\n sortValue = if (it.apim.rotation == 0f) {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 1\n } else {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 0\n }\n Thread {\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n\n private fun setModify() {\n if (ad?.exit == true) return\n line_shelf_modifier.apt.setText(R.string.menu_add_time)\n line_shelf_modifier.setOnClickListener {\n sortValue = if (it.apim.rotation == 0f) {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 3\n } else {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 2\n }\n Thread {\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n\n private fun setBrowse() {\n if (ad?.exit == true) return\n line_shelf_browse.apt.setText(R.string.menu_read_time)\n line_shelf_browse.setOnClickListener {\n sortValue = if (it.apim.rotation == 0f) {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 0f, 180f).setDuration(233).start()\n 5\n } else {\n ObjectAnimator.ofFloat(it.apim, \"rotation\", 180f, 0f).setDuration(233).start()\n 4\n }\n Thread {\n sleep(400)\n activity?.runOnUiThread {\n reset()\n addPage()\n }\n }.start()\n }\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt (date 1709910426026) -@@ -2,9 +2,14 @@ - - import android.animation.ObjectAnimator - import android.os.Bundle -+import android.view.View -+import androidx.lifecycle.lifecycleScope - import androidx.navigation.fragment.findNavController - import kotlinx.android.synthetic.main.anchor_popular.view.* - import kotlinx.android.synthetic.main.line_shelf.* -+import kotlinx.coroutines.Dispatchers -+import kotlinx.coroutines.launch -+import kotlinx.coroutines.withContext - import top.fumiama.copymanga.MainActivity - import top.fumiama.copymanga.template.ui.InfoCardLoader - import top.fumiama.copymanga.tools.api.CMApi -@@ -37,6 +42,7 @@ - - override fun setListeners() { - super.setListeners() -+ fade() - setUpdate() - setModify() - setBrowse() -@@ -46,20 +52,10 @@ - if (ad?.exit == true) return - line_shelf_updated.apt.setText(R.string.menu_update_time) - line_shelf_updated.setOnClickListener { -- sortValue = if (it.apim.rotation == 0f) { -- ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() -- 1 -- } else { -- ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() -- 0 -- } -- Thread { -- sleep(400) -- activity?.runOnUiThread { -- reset() -- addPage() -- } -- }.start() -+ val same = sortValue in 0..1 -+ sortValue = rotate(it.apim, same, 0) -+ if (!same) fade() -+ resetDelayed() - } - } - -@@ -67,20 +63,10 @@ - if (ad?.exit == true) return - line_shelf_modifier.apt.setText(R.string.menu_add_time) - line_shelf_modifier.setOnClickListener { -- sortValue = if (it.apim.rotation == 0f) { -- ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() -- 3 -- } else { -- ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() -- 2 -- } -- Thread { -- sleep(400) -- activity?.runOnUiThread { -- reset() -- addPage() -- } -- }.start() -+ val same = sortValue in 2..3 -+ sortValue = rotate(it.apim, same, 2) -+ if (!same) fade() -+ resetDelayed() - } - } - -@@ -88,20 +74,60 @@ - if (ad?.exit == true) return - line_shelf_browse.apt.setText(R.string.menu_read_time) - line_shelf_browse.setOnClickListener { -- sortValue = if (it.apim.rotation == 0f) { -- ObjectAnimator.ofFloat(it.apim, "rotation", 0f, 180f).setDuration(233).start() -- 5 -+ val same = sortValue>=4 -+ sortValue = rotate(it.apim, same, 4) -+ if (!same) fade() -+ resetDelayed() -+ } -+ } -+ -+ private fun rotate(img: View, isSameSlot: Boolean, offset: Int): Int { -+ return if (isSameSlot) { -+ if (img.rotation == 0f) { -+ ObjectAnimator.ofFloat(img, "rotation", 0f, 180f).setDuration(233).start() -+ offset+1 - } else { -- ObjectAnimator.ofFloat(it.apim, "rotation", 180f, 0f).setDuration(233).start() -- 4 -+ ObjectAnimator.ofFloat(img, "rotation", 180f, 0f).setDuration(233).start() -+ offset - } -- Thread { -+ } else { -+ if (img.rotation == 0f) { -+ offset -+ } else { -+ offset+1 -+ } -+ } -+ } -+ -+ private fun fade() { -+ when(sortValue) { -+ 0, 1 -> { -+ line_shelf_updated.alpha = 1f -+ line_shelf_modifier.alpha = 0.5f -+ line_shelf_browse.alpha = 0.5f -+ } -+ 2, 3 -> { -+ line_shelf_updated.alpha = 0.5f -+ line_shelf_modifier.alpha = 1f -+ line_shelf_browse.alpha = 0.5f -+ } -+ 4, 5 -> { -+ line_shelf_updated.alpha = 0.5f -+ line_shelf_modifier.alpha = 0.5f -+ line_shelf_browse.alpha = 1f -+ } -+ } -+ } -+ -+ private fun resetDelayed() { -+ lifecycleScope.launch { -+ withContext(Dispatchers.IO) { - sleep(400) -- activity?.runOnUiThread { -+ withContext(Dispatchers.Main) { - reset() - addPage() - } -- }.start() -+ } - } - } - } -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.json;\n\npublic class ComicStructure {\n public String uuid;\n public String name;\n public String alias;\n public ValueDisplayPair status;\n public ThemeStructure[] theme;\n public String path_word;\n public ThemeStructure[] author;\n public int img_type;\n public String brief;\n public String datetime_updated;\n public String cover;\n public int popular;\n}\n -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java b/app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java ---- a/app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/json/ComicStructure.java (date 1709888745347) -@@ -4,11 +4,12 @@ - public String uuid; - public String name; - public String alias; -+ public int img_type; -+ public ValueDisplayPair region; - public ValueDisplayPair status; - public ThemeStructure[] theme; - public String path_word; - public ThemeStructure[] author; -- public int img_type; - public String brief; - public String datetime_updated; - public String cover; -Index: app/src/main/res/drawable-anydpi/ic_image.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/drawable-anydpi/ic_image.xml b/app/src/main/res/drawable-anydpi/ic_image.xml -new file mode 100644 ---- /dev/null (date 1709889633320) -+++ b/app/src/main/res/drawable-anydpi/ic_image.xml (date 1709889633320) -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -\ No newline at end of file -Index: app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP -<+>package top.fumiama.copymanga.ui.cardflow.topic\n\nimport android.os.Bundle\nimport com.google.gson.Gson\nimport kotlinx.android.synthetic.main.app_bar_main.*\nimport kotlinx.android.synthetic.main.fragment_topic.*\nimport top.fumiama.copymanga.MainActivity.Companion.mainWeakReference\nimport top.fumiama.copymanga.json.TopicStructure\nimport top.fumiama.copymanga.template.http.AutoDownloadThread\nimport top.fumiama.copymanga.template.ui.InfoCardLoader\nimport top.fumiama.copymanga.tools.api.CMApi\nimport top.fumiama.dmzj.copymanga.R\n\n@ExperimentalStdlibApi\nclass TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_topic_to_nav_book) {\n private var type = 1\n override fun getApiUrl() =\n getString(R.string.topicContentApiUrl).format(CMApi.myHostApiUrl, arguments?.getString(\"path\"), type, offset)\n\n override fun onCreate(savedInstanceState: Bundle?) {\n super.onCreate(savedInstanceState)\n AutoDownloadThread(getString(R.string.topicApiUrl).format(CMApi.myHostApiUrl, arguments?.getString(\"path\"))) { data ->\n if(ad?.exit == true) return@AutoDownloadThread\n data?.apply {\n val r = inputStream().reader()\n val topic = Gson().fromJson(r, TopicStructure::class.java)\n topic?.apply {\n if(ad?.exit != false) return@AutoDownloadThread\n activity?.let {\n it.runOnUiThread {\n if(ad?.exit != false) return@runOnUiThread\n it.toolbar.title = results.title\n ftttime.text = results.datetime_created\n fttintro.text = results.intro\n type = results.type\n }\n }\n }\n }\n }.start()\n }\n} -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt ---- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt (revision 229d5b2088d8ccb7c11e4a5760a6c133ec95b101) -+++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt (date 1709906325403) -@@ -23,12 +23,11 @@ - if(ad?.exit == true) return@AutoDownloadThread - data?.apply { - val r = inputStream().reader() -- val topic = Gson().fromJson(r, TopicStructure::class.java) -- topic?.apply { -- if(ad?.exit != false) return@AutoDownloadThread -+ Gson().fromJson(r, TopicStructure::class.java)?.apply { -+ if(ad?.exit == true) return@AutoDownloadThread - activity?.let { - it.runOnUiThread { -- if(ad?.exit != false) return@runOnUiThread -+ if(ad?.exit == true) return@runOnUiThread - it.toolbar.title = results.title - ftttime.text = results.datetime_created - fttintro.text = results.intro -Index: app/src/main/res/drawable-anydpi/ic_data.xml -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/app/src/main/res/drawable-anydpi/ic_data.xml b/app/src/main/res/drawable-anydpi/ic_data.xml -new file mode 100644 ---- /dev/null (date 1709889542283) -+++ b/app/src/main/res/drawable-anydpi/ic_data.xml (date 1709889542283) -@@ -0,0 +1,10 @@ -+ -+ -+ -+ -\ No newline at end of file diff --git a/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9__12_23_AM__Changes_.xml b/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9__12_23_AM__Changes_.xml deleted file mode 100644 index 007eed3..0000000 --- a/.idea/shelf/Uncommitted_changes_before_Update_at_2024_3_9__12_23_AM__Changes_.xml +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 98799bc..afcfbc8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId 'top.fumiama.copymanga' minSdkVersion 23 targetSdkVersion 34 - versionCode 53 - versionName '2.2.5' + versionCode 54 + versionName '2.2.6' resourceConfigurations += ['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 index 77983e6..60db74b 100644 --- a/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt +++ b/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt @@ -24,13 +24,13 @@ class MangaDlTools { PausableDownloader(url.toString(), 1000) { data -> try { Gson().fromJson(data.decodeToString(), Chapter2Return::class.java)?.let { - getChapterInfo(it, index, chapterName, group) + downloadChapter(it, index, chapterName, group) } } catch (e: Exception) { e.printStackTrace() onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error") } - }.run() + }.run().let { if (!it) onDownloadedListener?.handleMessage(index, false, "获取章节信息错误") } } @Synchronized private fun prepareDownloadListener() { @@ -57,8 +57,8 @@ class MangaDlTools { indexMap[f] = index } - private fun getChapterInfo(chapter2Return: Chapter2Return, index: Int, chapterName: CharSequence, group: CharSequence) { - if(index >= 0){ + private fun downloadChapter(chapter2Return: Chapter2Return, index: Int, chapterName: CharSequence, group: CharSequence) { + if(index >= 0) { val f = "$chapterName.zip" setPool(chapter2Return.results.comic.name, group) setIndexMap(f, index) diff --git a/app/src/main/java/top/fumiama/copymanga/manga/Reader.kt b/app/src/main/java/top/fumiama/copymanga/manga/Reader.kt index c41f7d1..eb5d26f 100644 --- a/app/src/main/java/top/fumiama/copymanga/manga/Reader.kt +++ b/app/src/main/java/top/fumiama/copymanga/manga/Reader.kt @@ -5,38 +5,61 @@ import android.content.Intent import android.util.Log import androidx.core.content.edit import com.google.gson.Gson +import kotlinx.android.synthetic.main.button_tbutton.view.* import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.ui.vm.ViewMangaActivity import java.io.File object Reader { - fun start2viewManga(name: String, pos: Int, urlArray: Array, fromFirstPage: Boolean = false) { + var fileArray = arrayOf() + fun start2viewManga(name: String?, pos: Int, urlArray: Array, uuidArray: Array, fromFirstPage: Boolean = false) { Log.d("MyR", "viewMangaAt name $name, pos $pos") 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.position = pos - ViewMangaActivity.comicName = name - val zipf = ViewMangaActivity.fileArray[pos] 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) - if(!fromFirstPage) { + intent.putExtra("uuidArray", uuidArray) + if (!fromFirstPage) { intent.putExtra("function", "log") - ViewMangaActivity.pn = -2 + intent.putExtra("pn", -2) } - if (zipf.exists()) { - ViewMangaActivity.zipFile = zipf + val zipFile = fileArray[pos] + if (zipFile.exists()) { + intent.putExtra("zipFile", zipFile.absolutePath) //intent.putExtra("callFrom", "zipFirst") - startActivity(intent) - } else { - ViewMangaActivity.zipFile = null - startActivity(intent) } + startActivity(intent) + } + } + fun viewOldMangaZipFile(fileArray: Array, 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, uuidArray: Array, 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 { diff --git a/app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt b/app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt index 08e47bc..5a95a2b 100644 --- a/app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt +++ b/app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt @@ -8,12 +8,11 @@ import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.http.DownloadTools 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 isApi: Boolean = true, private val whenFinish: (suspend (result: ByteArray)->Unit)? = null) { var exit = false - suspend fun run() = withContext(Dispatchers.IO) { + suspend fun run(): Boolean = withContext(Dispatchers.IO) { var c = 0 while (!exit && c++ < 3) { try { @@ -23,12 +22,13 @@ class PausableDownloader(private val url: String, private val waitMilliseconds: mainWeakReference?.get()?.getString(R.string.pc_ua)!! )) whenFinish?.let { it(data) } - break + return@withContext true } catch (e: Exception) { e.printStackTrace() if (waitMilliseconds > 0) delay(200+Random.nextLong(waitMilliseconds)) } } Log.d("MyPD", "found exit = $exit") + return@withContext false } } 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 index 3422d54..fefa324 100644 --- a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt +++ b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt @@ -1,6 +1,9 @@ package top.fumiama.copymanga.tools.http import android.util.Log +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import top.fumiama.copymanga.tools.api.CMApi import java.io.File import java.io.FileOutputStream @@ -14,7 +17,7 @@ import java.util.zip.ZipOutputStream import kotlin.random.Random class DownloadPool(folder: String) { - class Quest(val fileName: String, val imgUrl: Array, val refer: String? = null) + class Quest(val fileName: String, val imgUrl: Array) var exit = false set(value) { if(value) { @@ -33,8 +36,9 @@ class DownloadPool(folder: String) { if(!saveFolder.exists()) saveFolder.mkdirs() } - operator fun plusAssign(quest: Quest) { + operator fun plusAssign(quest: Quest): Unit { packZipFile(quest.fileName, quest.imgUrl) + Log.d("MyDP", "+= ${quest.fileName}, size: ${quest.imgUrl.size}") } fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) { @@ -46,83 +50,81 @@ class DownloadPool(folder: String) { } private fun packZipFile(fileName: String, imgUrls: Array) { - Thread { - File(saveFolder, "$fileName.tmp").let { f -> - f.parentFile?.let { if(!it.exists()) it.mkdirs() } - var start = 0 - Log.d("MyDP", "Zip file: ${f.absolutePath}") - if(f.exists()) { - try { - val zipFile = ZipFile(f) - start = zipFile.size() - zipFile.close() - Log.d("MyDP", "next download index: $start") - if (start <= 0 || start >= imgUrls.size) { // error or re-download - f.delete() - f.createNewFile() - start = 0 - } - } catch (e: Exception) { - e.printStackTrace() + File(saveFolder, "$fileName.tmp").let { f -> + f.parentFile?.let { if(!it.exists()) it.mkdirs() } + var start = 0 + Log.d("MyDP", "Zip file: ${f.absolutePath}") + if(f.exists()) { + try { + val zipFile = ZipFile(f) + start = zipFile.size() + zipFile.close() + Log.d("MyDP", "next download index: $start") + if (start <= 0 || start >= imgUrls.size) { // error or re-download f.delete() 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) { 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") } + } + } } } \ 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 c516bfd..4a78c4a 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 @@ -115,15 +115,14 @@ object DownloadTools { fun prepare(url: String?): FutureTask? = url?.let { Log.d("Mydl", "prepareHttp: $it") - var ret: ByteArray? = null val task = FutureTask(Callable { + var ret: ByteArray? = null try { val connection = getNormalConnection(it, "GET") - - val ci = connection?.inputStream - ret = ci?.readBytes() - ci?.close() - connection?.disconnect() + connection.inputStream?.use { ci -> + ret = ci.readBytes() + } + connection.disconnect() } catch (ex: Exception) { ex.printStackTrace() } 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 891d481..018e0fa 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 @@ -105,8 +105,8 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { i = p } setOnClickListener { - mBookHandler?.urlArray?.let { - Reader.start2viewManga(name, i, it) + mBookHandler?.apply { + Reader.start2viewManga(name, i, urlArray, uuidArray) } } } 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 491c2cd..28df526 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 @@ -49,6 +49,7 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m var chapterNames = arrayOf() var collect: Int = -1 var urlArray = arrayOf() + var uuidArray = arrayOf() var exit = false override fun handleMessage(msg: Message) { @@ -210,7 +211,7 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) Log.d("MyBH", "add last single chapter ${it.name}") val index = i - setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) } + setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } } line?.let { l -> addVolumesView(fbl, l) } } else { @@ -219,14 +220,14 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m lct.text = it.name if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) val index = i - setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) } + setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } } } } else line?.l2cr?.apply { lct.text = it.name if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) val index = i - setOnClickListener { Reader.start2viewManga(comicName, index, urlArray) } + setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } line?.let { l -> addVolumesView(fbl, l) } line = null } @@ -242,9 +243,9 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m that?.apply { book?.apply { val comicName = name?:return@withContext - ViewMangaActivity.fileArray = arrayOf() + Reader.fileArray = arrayOf() urlArray = arrayOf() - ViewMangaActivity.uuidArray = arrayOf() + uuidArray = arrayOf() var i = 0 var last = -1 volumes.forEachIndexed { groupIndex, v -> @@ -256,9 +257,9 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m it.uuid )?:"" val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comicName, keys[groupIndex], it.name) - ViewMangaActivity.fileArray += f + Reader.fileArray += f chapterNames += it.name - ViewMangaActivity.uuidArray += it.uuid + uuidArray += it.uuid that?.isOnPause?.let { isOnPause -> while (isOnPause && !exit) delay(500) if (exit) return@withContext 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 353385d..7cdd949 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 @@ -3,7 +3,6 @@ package top.fumiama.copymanga.ui.comicdl import android.animation.ObjectAnimator import android.annotation.SuppressLint import android.app.Dialog -import android.content.Intent import android.os.Handler import android.os.Looper import android.os.Message @@ -13,29 +12,31 @@ import android.view.ViewTreeObserver import android.widget.Toast import androidx.lifecycle.lifecycleScope 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.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_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.launch import kotlinx.coroutines.withContext -import top.fumiama.dmzj.copymanga.R import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.json.ChapterStructure import top.fumiama.copymanga.json.ComicStructureOld import top.fumiama.copymanga.json.VolumeStructure -import top.fumiama.copymanga.tools.api.CMApi 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.ui.comicdl.ComicDlFragment.Companion.exit import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json import top.fumiama.copymanga.ui.vm.ViewMangaActivity import top.fumiama.copymanga.views.ChapterToggleButton import top.fumiama.copymanga.views.LazyScrollView +import top.fumiama.dmzj.copymanga.R import java.io.File import java.lang.ref.WeakReference @@ -62,6 +63,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference() var downloading = false private var urlArray = arrayOf() + private var uuidArray = arrayOf() @SuppressLint("SetTextI18n") override fun handleMessage(msg: Message) { @@ -111,8 +113,8 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference val caption = groupNames?.get(i)?:vol.results.list[0].group_path_word Log.d("MyCDH", "caption: $caption, group name: ${groupNames?.get(i)}") @@ -269,16 +271,14 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference { Toast.makeText(context, "加载中...", Toast.LENGTH_SHORT).show() - ViewMangaActivity.zipFile = chosenFile - ViewMangaActivity.comicName = it[position] - ViewMangaActivity.position = position - ViewMangaActivity.fileArray = it.map { File(cd, it) }.toTypedArray() - // ViewMangaActivity.urlArray = Array(it.size) {return@Array ""} - startActivity(Intent(context, ViewMangaActivity::class.java)) + Reader.viewOldMangaZipFile( + it.map { File(cd, it) }.toTypedArray(), + it[position], position, chosenFile + ) } } } diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt index 27c3aa1..4a93f0b 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt @@ -2,8 +2,6 @@ package top.fumiama.copymanga.ui.vm import android.widget.Toast 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 java.lang.ref.WeakReference @@ -38,7 +36,7 @@ class PagesManager(private val w: WeakReference) { } return } - val chapterPosition = position + if(goNext) 1 else -1 + val chapterPosition = v.position + if(goNext) 1 else -1 if (v.urlArray.isEmpty()) return if(chapterPosition < 0 || chapterPosition >= v.urlArray.size) { Toast.makeText(v.applicationContext, R.string.end_of_chapter, Toast.LENGTH_SHORT).show() @@ -48,7 +46,7 @@ class PagesManager(private val w: WeakReference) { //if(v.zipFirst) intent.putExtra("callFrom", "zipFirst") v.tt.canDo = false //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() return } 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 5c9c422..d15a227 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 @@ -9,10 +9,12 @@ import android.view.View import androidx.lifecycle.lifecycleScope import com.google.gson.Gson 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.view.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import top.fumiama.copymanga.MainActivity 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.template.http.AutoDownloadHandler 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.dmzj.copymanga.R 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() } RESTORE_PAGE_NUMBER -> { sendEmptyMessage(DIALOG_HIDE) - wv.get()?.restorePN() + wv.get()?.apply { lifecycleScope.launch { restorePN() } } } LOAD_PAGE_FROM_ITEM -> { val verticalMaxCount = wv.get()?.verticalLoadMaxCount?:20 - val item = (pn - 1) / verticalMaxCount * verticalMaxCount + val item = ((wv.get()?.pn?:1) - 1) / verticalMaxCount * verticalMaxCount loadScrollMode(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() 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 @@ -159,9 +158,9 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri prepareManga() } - suspend fun loadFromFile(file: File): Boolean = withContext(Dispatchers.IO) { + suspend fun loadFromFile(file: File): Boolean { fakeLoad() - return@withContext try { + return try { val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json") if(jsonFile.exists()) { manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java) @@ -172,13 +171,15 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri manga?.let { it.results = Chapter2Return.Results() 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.name = file.nameWithoutExtension - it.results.chapter.uuid = uuidArray[position] - wv.get()?.countZipEntries { c -> - it.results.chapter.size = c - prepareManga() + wv.get()?.apply { + it.results.chapter.uuid = uuidArray[position] + countZipEntries { c -> + 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) { - if(MainActivity.member?.hasLogin == true) launch { - PausableDownloader(chapterUrl) { _ -> }.run() - } + private fun fakeLoad() { + if (MainActivity.member?.hasLogin == true) Thread { + runBlocking { PausableDownloader(chapterUrl) { _ -> }.run() } + }.start() } private suspend fun prepareManga() = withContext(Dispatchers.Main) { - if(comicName == null) { - comicName = manga?.results?.comic?.name + wv.get()?.apply { + 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) { 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() obtainMessage(DO_LAMBDA, Runnable{ doAfter?.run() - wv.get()?.updateSeekBar(0) + wv.get()?.apply { lifecycleScope.launch { updateSeekBar(0) } } }).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 DO_LAMBDA = 21 const val SET_NET_INFO = 22 + const val SET_DL_TEXT = 23 } } \ No newline at end of file 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 89d925f..9fdcbda 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 @@ -12,10 +12,14 @@ import android.graphics.drawable.Drawable import android.media.AudioManager import android.os.Bundle import android.os.Handler -import android.os.Looper import android.util.Log 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.Toast import androidx.appcompat.app.AppCompatDelegate @@ -115,6 +119,11 @@ class ViewMangaActivity : TitleActivityTemplate() { val realCount get() = if(cut) indexMap.size else count var urlArray = arrayOf() + var uuidArray = arrayOf() + var position = 0 + var comicName: String? = null + private var zipFile: File? = null + var pn = 0 private val loadImgOnWait = AtomicInteger() @@ -149,6 +158,11 @@ class ViewMangaActivity : TitleActivityTemplate() { //dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true" //zipFirst = intent.getStringExtra("callFrom") == "zipFirst" 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"] r2l = pb["r2l"] 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) { isInScroll = false pageNum = pn @@ -242,41 +256,51 @@ class ViewMangaActivity : TitleActivityTemplate() { } @ExperimentalStdlibApi - private fun doPrepareWebImg() = Thread { + private suspend fun doPrepareWebImg() = withContext(Dispatchers.IO) { getImgUrlArray()?.apply { if(cut) { Log.d("MyVM", "is cut, load all pages...") - handler.sendEmptyMessage(VMHandler.DIALOG_SHOW) //showDl + handler.sendEmptyMessage(VMHandler.DIALOG_SHOW) // showDl isCut = BooleanArray(size) - val analyzedCnt = BooleanArray(size) forEachIndexed { i, it -> - if(it != null) { - Thread{ - DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let { - isCut[i] = canCut(it) - analyzedCnt[i] = true + handler.obtainMessage(VMHandler.SET_DL_TEXT, "$i/$size").sendToTarget() + if(it != null) try { + DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let { + isCut[i] = canCut(it) + }?:run { + withContext(Dispatchers.Main) { + Toast.makeText(this@ViewMangaActivity, R.string.touch_img_error, Toast.LENGTH_SHORT) + .show() + finish() } - }.start() - Thread.sleep(22) + return@withContext + } + } 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 -> Log.d("MyVM", "[$index] cut: $b") indexMap += index+1 if(b) indexMap += -(index+1) } - handler.sendEmptyMessage(15) //hideDl + handler.sendEmptyMessage(15) // hideDl Log.d("MyVM", "load all pages finished") } count = size - runOnUiThread { prepareItems() } + prepareItems() if (notUseVP) prepareDownloadTasks() } - }.start() + } @OptIn(ExperimentalStdlibApi::class) - fun initManga() { + suspend fun initManga() = withContext(Dispatchers.IO) { val uuid = handler.manga?.results?.chapter?.uuid Log.d("MyVM", "initManga, chapter uuid: $uuid") if (uuid != null && uuid != "") { @@ -333,14 +357,13 @@ class ViewMangaActivity : TitleActivityTemplate() { Log.d("MyVM", "setPageNumber($num)") if (r2l && !notUseVP) vp.currentItem = realCount - num else if (notUseVP) { - if(isVertical){ + if(isVertical) { currentItem = num - 1 val offset = currentItem % verticalLoadMaxCount Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}") if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size - updateSeekBar() - } - else { + lifecycleScope.launch { updateSeekBar() } + } else { currentItem = num - 1 try { loadOneImg() @@ -353,23 +376,24 @@ class ViewMangaActivity : TitleActivityTemplate() { } } else { Log.d("MyVM", "Set vp current: ${num-1}") - var delta = num - 1 - vp.currentItem - if(delta >= 1) Thread{ - while (delta-- > 0){ - Thread.sleep(23) - runOnUiThread { - vp.currentItem++ + //var delta = num - 1 - vp.currentItem + vp.currentItem = num - 1 + /*lifecycleScope.launch { + withContext(Dispatchers.IO) { + if(delta >= 1) while (delta-- > 0){ + 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 @SuppressLint("SetTextI18n") - private fun prepareItems() { + private suspend fun prepareItems(): Unit = withContext(Dispatchers.Main) { try { prepareVP() prepareInfoBar() @@ -588,7 +612,7 @@ class ViewMangaActivity : TitleActivityTemplate() { } } - private fun setProgress() { + private suspend fun setProgress() = withContext(Dispatchers.IO) { handler.manga?.results?.chapter?.uuid?.let { getPreferences(MODE_PRIVATE).edit { //it["chapterId"] = hm.chapterId.toString() @@ -653,18 +677,18 @@ class ViewMangaActivity : TitleActivityTemplate() { vp.adapter = ViewData(vp).RecyclerViewAdapter() vp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { - updateSeekBar() super.onPageSelected(position) + lifecycleScope.launch { updateSeekBar() } } }) if (r2l && !isPnValid) vp.currentItem = realCount - 1 } } - fun updateSeekBar(p: Int = 0) { + suspend fun updateSeekBar(p: Int = 0) = withContext(Dispatchers.Main) { if (p > 0) { updateSeekText(p) - return + return@withContext } if (!isInSeek) hideDrawer() updateSeekText() @@ -677,7 +701,7 @@ class ViewMangaActivity : TitleActivityTemplate() { oneinfo.alpha = 0F infseek.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" infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { var p = 0 @@ -726,7 +750,7 @@ class ViewMangaActivity : TitleActivityTemplate() { } else isInSeek = false } 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) @@ -786,7 +810,7 @@ class ViewMangaActivity : TitleActivityTemplate() { if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) { Log.d("MyVM", "Do scroll back, isVertical: $isVertical, pageNum: $pageNum") if (isInSeek) { - updateSeekBar(pageNum-1) + (pageNum-1).let { lifecycleScope.launch { updateSeekBar(it) } } return } handler.obtainMessage( @@ -805,7 +829,7 @@ class ViewMangaActivity : TitleActivityTemplate() { pageNum++ if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) { if (isInSeek) { - updateSeekBar(pageNum+1) + (pageNum+1).let { lifecycleScope.launch { updateSeekBar(it) } } return } handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE) @@ -917,14 +941,8 @@ class ViewMangaActivity : TitleActivityTemplate() { } companion object { - var comicName: String? = null - var uuidArray = arrayOf() - var fileArray = arrayOf() - var position = 0 - var zipFile: File? = null var dlHandler: Handler? = null var va: WeakReference? = null - var pn = 0 var noCellarAlert = false } } \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/user/Member.kt b/app/src/main/java/top/fumiama/copymanga/user/Member.kt index 47d3b60..176250d 100644 --- a/app/src/main/java/top/fumiama/copymanga/user/Member.kt +++ b/app/src/main/java/top/fumiama/copymanga/user/Member.kt @@ -3,7 +3,6 @@ package top.fumiama.copymanga.user import android.content.SharedPreferences import android.util.Base64 import com.google.gson.Gson -import com.google.gson.stream.JsonReader import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext 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) { val hasLogin: Boolean get() = pref.getString("token", "")?.isNotEmpty()?:false suspend fun login(username: String, pwd: String, salt: Int): LoginInfoStructure = withContext(Dispatchers.IO) { - try { - getLoginConnection(username, pwd, salt).apply { - Gson().fromJson( - JsonReader(inputStream.reader()), LoginInfoStructure::class.java - )?.let { data -> - disconnect() - if(data.code == 200) { - pref.edit()?.apply { - putString("token", data.results?.token) - putString("user_id", data.results?.user_id) - putString("username", data.results?.username) - putString("nickname", data.results?.nickname) - apply() - return@withContext info() + var err = "" + getLoginConnection(username, pwd, salt).apply { + inputStream.use { + it?.readBytes()?.let { data -> + data.inputStream().use { dataIn -> + try { + Gson().fromJson( + dataIn.reader(), LoginInfoStructure::class.java + )?.let { info -> + if(info.code == 200) { + pref.edit()?.apply { + putString("token", info.results?.token) + putString("user_id", info.results?.user_id) + 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) return@withContext l } - return@withContext try { - val l = Gson().fromJson(DownloadTools.getHttpContent( + try { + val data = DownloadTools.getHttpContent( getString(R.string.memberInfoApiUrl).format(CMApi.myHostApiUrl).let { CMApi.apiProxy?.wrap(it)?:it } - ).decodeToString(), - LoginInfoStructure::class.java) - if(l.code == 200) pref.edit()?.apply { - putString("avatar", l.results.avatar) - apply() + ).decodeToString() + try { + val l = Gson().fromJson(data, LoginInfoStructure::class.java) + if(l.code == 200) pref.edit()?.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) { val l = LoginInfoStructure() l.code = 450 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78c6523..6f6133d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,6 +56,8 @@ 第%1$d页加载异常 加载章节错误 图片加载错误,请尝试下载后使用较低图片质量查看 + 预载图片头失败 + 读取图片大小失败 https://%1$s/api/v3/h5/homeIndex?platform=3 https://%1$s @@ -171,7 +173,8 @@ 用户名为空 密码为空 登录失败 - 恢复登录失败 + 解析返回数据失败 + 获取用户信息失败 重启应用以彻底退出登录 前往旧版下载