From 335d860b0ddbc2b927dfa76c64a44cc5b0c617e0 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: Sun, 10 Mar 2024 03:14:23 +0900
Subject: [PATCH] =?UTF-8?q?v2.2.0=20=E4=BF=AE=E5=A4=8D=201.=20=E8=AF=A6?=
=?UTF-8?q?=E6=83=85=E9=A1=B5=E6=8C=89=E9=92=AE=E5=9C=A8=E6=9F=90=E4=BA=9B?=
=?UTF-8?q?=E6=9C=BA=E5=9E=8B=E6=98=BE=E7=A4=BA=E4=B8=8D=E5=85=A8=202.=20?=
=?UTF-8?q?=E5=9B=BE=E5=BA=8A=E4=BB=A3=E7=90=86=E4=B8=8D=E6=AD=A3=E7=A1=AE?=
=?UTF-8?q?=E6=89=93=E5=BC=80=E5=AF=BC=E8=87=B4=E7=9A=84=E9=97=AA=E9=80=80?=
=?UTF-8?q?=203.=20=E4=B8=8B=E8=BD=BD=E4=B8=AD=E5=8F=96=E6=B6=88=E9=80=89?=
=?UTF-8?q?=E6=8B=A9=E5=88=99=E9=97=AA=E9=80=80=204.=20=E6=96=AD=E7=82=B9?=
=?UTF-8?q?=E7=BB=A7=E7=BB=AD=E4=B8=8B=E8=BD=BD=E7=9A=84zip=E9=94=99?=
=?UTF-8?q?=E8=AF=AF=205.=20=E6=B5=8F=E8=A7=88=E5=8E=86=E5=8F=B2=E6=A0=87?=
=?UTF-8?q?=E8=AE=B0=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF=206.=20=E6=B5=8F?=
=?UTF-8?q?=E8=A7=88=E5=B7=B2=E4=B8=8B=E8=BD=BD=E7=AB=A0=E8=8A=82=E6=97=B6?=
=?UTF-8?q?=E4=B8=8D=E8=83=BD=E8=AE=B0=E5=BD=95=E5=88=B0=E4=BA=91=E7=AB=AF?=
=?UTF-8?q?=207.=20=E8=BF=9B=E5=85=B6=E4=BB=96=E4=B9=A6=E8=BF=94=E5=9B=9E?=
=?UTF-8?q?=E5=90=8E=E6=BC=AB=E7=94=BB=E4=B8=8B=E8=BD=BD=E5=8F=98=E4=B8=BA?=
=?UTF-8?q?=E6=9C=80=E4=B8=8A=E5=B1=82=20=E4=BC=98=E5=8C=96=201.=20?=
=?UTF-8?q?=E8=BF=9B=E4=B8=80=E6=AD=A5=E5=8D=8F=E7=A8=8B=E5=8C=96CardList,?=
=?UTF-8?q?=20HTTP/=E6=96=87=E4=BB=B6=E8=AF=BB=E5=86=99=E7=AD=89=202.=20?=
=?UTF-8?q?=E5=90=84=E6=A8=A1=E5=9D=97=E5=8A=A0=E8=BD=BD=E9=80=9F=E5=BA=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/dictionaries/fumiama.xml | 2 +
app/build.gradle | 17 +-
.../top/fumiama/copymanga/MainActivity.kt | 5 +-
.../java/top/fumiama/copymanga/manga/Book.kt | 10 +
.../fumiama/copymanga/manga/MangaDlTools.kt | 10 +-
.../java/top/fumiama/copymanga/manga/Shelf.kt | 9 +-
.../template/general/ActivityTemplate.kt | 2 +-
.../template/general/NoBackRefreshFragment.kt | 2 +-
.../template/http/AutoDownloadHandler.kt | 69 ++---
.../template/http/AutoDownloadThread.kt | 25 --
.../template/http/PausableDownloader.kt | 30 +++
.../fumiama/copymanga/template/ui/CardList.kt | 84 +++---
.../copymanga/template/ui/InfoCardLoader.kt | 39 +--
.../top/fumiama/copymanga/tools/api/CMApi.kt | 66 ++---
.../copymanga/tools/http/DownloadPool.kt | 42 +--
.../copymanga/tools/http/DownloadTools.kt | 58 ++---
.../top/fumiama/copymanga/tools/http/Proxy.kt | 19 +-
.../copymanga/tools/thread/TimeThread.kt | 4 +-
.../top/fumiama/copymanga/tools/ui/UITools.kt | 6 +-
.../fumiama/copymanga/ui/book/BookFragment.kt | 32 ++-
.../fumiama/copymanga/ui/book/BookHandler.kt | 176 +++++++------
.../ui/cardflow/sort/SortFragment.kt | 152 +++++------
.../ui/cardflow/topic/TopicFragment.kt | 42 +--
.../copymanga/ui/comicdl/ComicDlFragment.kt | 94 ++++---
.../copymanga/ui/comicdl/ComicDlHandler.kt | 244 ++++++++++--------
.../copymanga/ui/download/DownloadFragment.kt | 7 +-
.../ui/download/NewDownloadFragment.kt | 3 +-
.../fumiama/copymanga/ui/home/HomeFragment.kt | 66 +++--
.../fumiama/copymanga/ui/home/HomeHandler.kt | 122 ++++-----
.../top/fumiama/copymanga/ui/vm/VMHandler.kt | 49 ++--
.../copymanga/ui/vm/ViewMangaActivity.kt | 228 ++++++++--------
.../java/top/fumiama/copymanga/user/Member.kt | 67 +++--
.../fumiama/copymanga/views/ScaleImageView.kt | 8 +-
app/src/main/res/layout/line_bookinfo.xml | 4 +-
app/src/main/res/values/strings.xml | 6 +-
35 files changed, 988 insertions(+), 811 deletions(-)
create mode 100644 app/src/main/java/top/fumiama/copymanga/manga/Book.kt
delete mode 100644 app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt
create mode 100644 app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt
diff --git a/.idea/dictionaries/fumiama.xml b/.idea/dictionaries/fumiama.xml
index 9904d8f..fe0a67e 100644
--- a/.idea/dictionaries/fumiama.xml
+++ b/.idea/dictionaries/fumiama.xml
@@ -3,7 +3,9 @@
imgs
lowpan
+ mangafuna
nisi
+ pausable
reilia
diff --git a/app/build.gradle b/app/build.gradle
index 4c9f419..8ed6a3b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,19 +8,32 @@ android {
applicationId 'top.fumiama.copymanga'
minSdkVersion 23
targetSdkVersion 34
- versionCode 46
- versionName '2.1.3'
+ versionCode 47
+ versionName '2.2.0'
resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ aaptOptions {
+ cruncherEnabled = false
+ }
}
+ signingConfigs {
+ release {
+ enableV1Signing true
+ enableV2Signing true
+ enableV3Signing true
+ enableV4Signing true
+ }
+ }
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.release
}
/*winrelease {
minifyEnabled true
diff --git a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt
index 07b4942..d96738d 100644
--- a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt
+++ b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt
@@ -156,7 +156,7 @@ class MainActivity : AppCompatActivity() {
true
}
R.id.action_download -> {
- bookHandler?.sendEmptyMessage(6)
+ bookHandler.get()?.sendEmptyMessage(6)
true
}
R.id.action_sort -> {
@@ -213,6 +213,7 @@ class MainActivity : AppCompatActivity() {
Glide.with(this@MainActivity).load(avatar)
.apply(RequestOptions.bitmapTransform(CircleCrop()))
.into(navhicon)
+ else navhicon.setImageResource(R.mipmap.ic_launcher)
}
}
@@ -371,7 +372,7 @@ class MainActivity : AppCompatActivity() {
startActivity(Intent(this, LoginActivity::class.java))
}
- companion object{
+ companion object {
var mainWeakReference: WeakReference? = null
var isDrawerClosed = true
var ime: InputMethodManager? = null
diff --git a/app/src/main/java/top/fumiama/copymanga/manga/Book.kt b/app/src/main/java/top/fumiama/copymanga/manga/Book.kt
new file mode 100644
index 0000000..b5d1c60
--- /dev/null
+++ b/app/src/main/java/top/fumiama/copymanga/manga/Book.kt
@@ -0,0 +1,10 @@
+package top.fumiama.copymanga.manga
+
+class Book(val pathWord: String, val readLocally: Boolean = false) {
+ /**
+ * 更新云端最新信息
+ */
+ suspend fun update() {
+
+ }
+}
\ No newline at end of file
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 10cb03f..77983e6 100644
--- a/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt
+++ b/app/src/main/java/top/fumiama/copymanga/manga/MangaDlTools.kt
@@ -4,7 +4,7 @@ import android.util.Log
import com.google.gson.Gson
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.Chapter2Return
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.http.DownloadPool
import java.io.File
@@ -19,18 +19,18 @@ class MangaDlTools {
get() = pool?.wait
set(value) { if (value != null) { pool?.wait = value } }
- fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int) {
+ suspend fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int) {
Log.d("MyMDT", "下载:$url, index:$index")
- AutoDownloadThread(url.toString(), 1000) { data ->
+ PausableDownloader(url.toString(), 1000) { data ->
try {
- Gson().fromJson(data?.decodeToString(), Chapter2Return::class.java)?.let {
+ Gson().fromJson(data.decodeToString(), Chapter2Return::class.java)?.let {
getChapterInfo(it, index, chapterName, group)
}
} catch (e: Exception) {
e.printStackTrace()
onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error")
}
- }.start()
+ }.run()
}
@Synchronized private fun prepareDownloadListener() {
diff --git a/app/src/main/java/top/fumiama/copymanga/manga/Shelf.kt b/app/src/main/java/top/fumiama/copymanga/manga/Shelf.kt
index 8974803..428f32f 100644
--- a/app/src/main/java/top/fumiama/copymanga/manga/Shelf.kt
+++ b/app/src/main/java/top/fumiama/copymanga/manga/Shelf.kt
@@ -51,8 +51,13 @@ class Shelf(private val token: String, getString: (Int) -> String) {
}
suspend fun query(pathWord: String): BookQueryStructure? = withContext(Dispatchers.IO) {
- return@withContext DownloadTools.getHttpContent(queryApiUrl.format(hostUrl, pathWord), referer, ua)?.let {
- Gson().fromJson(it.decodeToString(), BookQueryStructure::class.java)
+ try {
+ Gson().fromJson(DownloadTools.getHttpContent(
+ queryApiUrl.format(hostUrl, pathWord), referer, ua
+ ).decodeToString(), BookQueryStructure::class.java)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
}
}
}
diff --git a/app/src/main/java/top/fumiama/copymanga/template/general/ActivityTemplate.kt b/app/src/main/java/top/fumiama/copymanga/template/general/ActivityTemplate.kt
index c3d8dfb..9e09190 100644
--- a/app/src/main/java/top/fumiama/copymanga/template/general/ActivityTemplate.kt
+++ b/app/src/main/java/top/fumiama/copymanga/template/general/ActivityTemplate.kt
@@ -7,7 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import top.fumiama.copymanga.tools.ui.UITools
-open class ActivityTemplate:AppCompatActivity() {
+open class ActivityTemplate: AppCompatActivity() {
lateinit var toolsBox: UITools
val pb = BoolPref()
private val allFullScreen
diff --git a/app/src/main/java/top/fumiama/copymanga/template/general/NoBackRefreshFragment.kt b/app/src/main/java/top/fumiama/copymanga/template/general/NoBackRefreshFragment.kt
index 84ff2e0..29b338d 100644
--- a/app/src/main/java/top/fumiama/copymanga/template/general/NoBackRefreshFragment.kt
+++ b/app/src/main/java/top/fumiama/copymanga/template/general/NoBackRefreshFragment.kt
@@ -18,7 +18,7 @@ open class NoBackRefreshFragment(private val layoutToLoad: Int): Fragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- if(_rootView == null){
+ if(_rootView == null) {
isFirstInflate = true
_rootView = inflater.inflate(layoutToLoad, container, false)
Log.d("MyNBRF", "is first inflate")
diff --git a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt
index 1da6e33..5de469a 100644
--- a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt
+++ b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadHandler.kt
@@ -4,21 +4,30 @@ import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
-import top.fumiama.dmzj.copymanga.R
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.ReturnBase
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.thread.TimeThread
+import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
import java.security.MessageDigest
-open class AutoDownloadHandler(private val url: String, private val jsonClass: Class<*>, looper: Looper, private val callCheckMsg: Int = -1, private val loadFromCache: Boolean = false, private val customCacheFile: File? = null): Handler(looper) {
- var exit = false
+open class AutoDownloadHandler(
+ private val url: String, private val jsonClass: Class<*>,
+ private val context: LifecycleOwner?,
+ private val callCheckMsg: Int = -1,
+ private val loadFromCache: Boolean = false,
+ private val customCacheFile: File? = null): Handler(Looper.myLooper()!!) {
private var timeThread: TimeThread? = null
private var checkTimes = 0
- private var cnt = 0
+ var exit = false
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when(msg.what){
@@ -29,19 +38,21 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C
open fun setGsonItem(gsonObj: Any): Boolean = true
open fun getGsonItem(): ReturnBase? = null
open fun onError() {}
- open fun doWhenFinishDownload() {}
+ open suspend fun doWhenFinishDownload() {}
fun startLoad() {
sendEmptyMessage(0)
}
fun destroy() {
exit = true
}
- private fun download() {
- Thread{ dlThread() }.start()
+ private suspend fun download() = withContext(Dispatchers.IO) {
checkTimes = 0
- timeThread = TimeThread(this, callCheckMsg)
- timeThread?.canDo = true
- timeThread?.start()
+ TimeThread(this@AutoDownloadHandler, callCheckMsg, 100).let {
+ timeThread = it
+ it.canDo = true
+ it.start()
+ }
+ downloadCoroutine()
}
private fun toHexStr(byteArray: ByteArray) =
with(StringBuilder()) {
@@ -53,7 +64,7 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C
}
toString()
}
- private fun dlThread() {
+ private suspend fun downloadCoroutine() = withContext(Dispatchers.IO) {
val cacheName = toHexStr(MessageDigest.getInstance("MD5").digest(url.encodeToByteArray()))
val cacheFile = customCacheFile?:(mainWeakReference?.get()?.externalCacheDir?.let { File(it, cacheName) })
if(loadFromCache) {
@@ -67,31 +78,29 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C
e.printStackTrace()
}
fi.close()
- if (pass) return
+ if (pass) return@withContext
}
}
}
- DownloadTools.getHttpContent(url, null, mainWeakReference?.get()?.getString(R.string.pc_ua)!!).let {
- if(exit) return
- if(it == null) {
- if (cnt++>3) return
- sleep(2000)
- dlThread()
- return
- }
- val fi = it.inputStream()
- var pass = true
+ var cnt = 0
+ while (cnt++ <= 3) {
try {
- pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass))
+ val data = DownloadTools.getHttpContent(url, null, mainWeakReference?.get()?.getString(R.string.pc_ua)!!)
+ if(exit) return@withContext
+ val fi = data.inputStream()
+ val pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass))
if (pass && loadFromCache) {
- cacheFile?.writeBytes(it)
+ cacheFile?.writeBytes(data)
}
+ fi.close()
+ if(!pass) {
+ sleep(2000)
+ continue
+ }
+ break
} catch (e: Exception) {
e.printStackTrace()
- }
- fi.close()
- if(!pass) {
- dlThread()
+ sleep(2000)
}
}
}
@@ -102,9 +111,9 @@ open class AutoDownloadHandler(private val url: String, private val jsonClass: C
if(g.code == 200) sendEmptyMessage(0)
else onError()
Log.d("MyADH", "[${g.code}]${g.message}")
- } else if(checkTimes++ > 3) timeThread?.canDo = false
+ } else if(checkTimes++ > 1000) timeThread?.canDo = false
}
- private fun setLayouts() {
+ private fun setLayouts() = context?.lifecycleScope?.launch {
if(getGsonItem() == null) download()
else doWhenFinishDownload()
}
diff --git a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt
deleted file mode 100644
index 1137c35..0000000
--- a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package top.fumiama.copymanga.template.http
-
-import android.util.Log
-import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
-import top.fumiama.copymanga.tools.http.DownloadTools
-import top.fumiama.dmzj.copymanga.R
-import kotlin.random.Random
-
-class AutoDownloadThread(private val url: String, private val waitMilliseconds: Long = 0, private val whenFinish: (result: ByteArray?)->Unit): Thread() {
- var exit = false
- override fun run() {
- super.run()
- var re: ByteArray? = null
- var c = 0
- while (!exit && re == null && c++ < 3) {
- if (waitMilliseconds > 0) sleep(200+Random.nextLong(waitMilliseconds))
- re = DownloadTools.getHttpContent(url,
- mainWeakReference?.get()?.getString(R.string.referer)!!,
- mainWeakReference?.get()?.getString(R.string.pc_ua)!!
- )
- }
- if(!exit) whenFinish(re)
- Log.d("MyADT", "found exit = $exit")
- }
-}
\ No newline at end of file
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
new file mode 100644
index 0000000..99a38d1
--- /dev/null
+++ b/app/src/main/java/top/fumiama/copymanga/template/http/PausableDownloader.kt
@@ -0,0 +1,30 @@
+package top.fumiama.copymanga.template.http
+
+import android.util.Log
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
+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 whenFinish: suspend (result: ByteArray)->Unit) {
+ var exit = false
+ suspend fun run() = withContext(Dispatchers.IO) {
+ var c = 0
+ while (!exit && c++ < 3) {
+ try {
+ whenFinish(DownloadTools.getHttpContent(url,
+ mainWeakReference?.get()?.getString(R.string.referer)!!,
+ mainWeakReference?.get()?.getString(R.string.pc_ua)!!
+ ))
+ break
+ } catch (e: Exception) {
+ e.printStackTrace()
+ if (waitMilliseconds > 0) sleep(200+Random.nextLong(waitMilliseconds))
+ }
+ }
+ Log.d("MyPD", "found exit = $exit")
+ }
+}
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
index 7f9b742..bcc9912 100644
--- a/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt
+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt
@@ -10,6 +10,8 @@ import com.bumptech.glide.load.model.GlideUrl
import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
import kotlinx.android.synthetic.main.line_lazybooklines.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.dmzj.copymanga.R
@@ -31,7 +33,7 @@ class CardList(
var initClickListeners: InitClickListeners? = null
var exitCardList = false
- fun reset(){
+ fun reset() {
rows = arrayOfNulls(20)
index = 0
count = 0
@@ -39,18 +41,18 @@ class CardList(
exitCardList = false
}
- private fun manageRow() {
+ private suspend fun manageRow() {
if(!exitCardList && count++ % cardPerRow == 0) inflateRow()
Log.d("MyCL", "index: $index, cardPR: $cardPerRow")
}
- private fun inflateRow(){
+ private suspend fun inflateRow() = withContext(Dispatchers.IO) {
that?.apply {
layoutInflater.inflate(R.layout.line_horizonal_empty, mydll, false)?.let {
- if(exitCardList) return
+ if(exitCardList) return@withContext
it.layoutParams.height = cardHeight + 16
- activity?.runOnUiThread {
- if(exitCardList) return@runOnUiThread
+ withContext(Dispatchers.Main) withMainContext@ {
+ if(exitCardList) return@withMainContext
mydll?.addView(it)
}
recycleOneRow(it)
@@ -58,14 +60,14 @@ class CardList(
}
}
}
- private fun recycleOneRow(v:View?){
+ private suspend fun recycleOneRow(v:View?) = withContext(Dispatchers.IO) {
val relativeIndex = index % 20
if(rows[relativeIndex] == null) rows[relativeIndex] = v
else {
val victim = rows[relativeIndex]
that?.apply {
- activity?.runOnUiThread {
- if(exitCardList) return@runOnUiThread
+ withContext(Dispatchers.Main) withMainContext@ {
+ if(exitCardList) return@withMainContext
mydll?.removeView(victim)
mys?.scrollY = mys?.scrollY?.minus(cardHeight + 16)?:0
}
@@ -75,8 +77,9 @@ class CardList(
}
@ExperimentalStdlibApi
- 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) {
- if (exitCardList) return
+ suspend 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) =
+ withContext(Dispatchers.IO) {
+ if (exitCardList) return@withContext
manageRow()
that?.apply {
layoutInflater.inflate(R.layout.card_book, mydll?.ltbtn, false)?.let {
@@ -90,26 +93,23 @@ class CardList(
card.pageNumber = pn
card.isFinish = isFinish
card.isNew = isNew
- activity?.runOnUiThread {
- if (exitCardList) return@runOnUiThread
- addCard(it)
- }
+ addCard(it)
}
}
}
@SuppressLint("SetTextI18n")
@ExperimentalStdlibApi
- fun addCard(cardFrame: View) {
+ private suspend fun addCard(cardFrame: View) = withContext(Dispatchers.IO) withIO@ {
val card = cardFrame.cic
- if (card.index < 0) return
+ if (card.index < 0) return@withIO
val name = card.name + (card.append?:"")
val head = card.headImageUrl
val file = File(that?.context?.getExternalFilesDir(""), card.name)
- if(exitCardList) return
+ if(exitCardList) return@withIO
cardFrame.let {
- it.tic.text = name
- if(!file.exists()){
+ withContext(Dispatchers.Main) { it.tic.text = name }
+ if(!file.exists()) {
if(head != null) {
that?.context?.let { context ->
val waitMillis = cardLoadingWaits.getAndIncrement().toLong()*200
@@ -119,35 +119,45 @@ class CardList(
if (exitCardList) return@GlideHideLottieViewListener
cardLoadingWaits.decrementAndGet()
})
- if (waitMillis > 0) it.imic.postDelayed({
- if (exitCardList) return@postDelayed
- g.into(it.imic)
- }, waitMillis) else g.into(it.imic)
+ withContext(Dispatchers.Main) {
+ if (waitMillis > 0) it.imic.postDelayed({
+ if (exitCardList) return@postDelayed
+ g.into(it.imic)
+ }, waitMillis) else g.into(it.imic)
+ }
}
- } else {
+ } else withContext(Dispatchers.Main) {
it.laic.pauseAnimation()
it.laic.visibility = View.GONE
it.imic.setImageResource(R.drawable.img_defmask)
}
} else {
val img = File(file, "head.jpg")
- it.laic.pauseAnimation()
- it.laic.visibility = View.GONE
+ withContext(Dispatchers.Main) {
+ it.laic.pauseAnimation()
+ it.laic.visibility = View.GONE
+ }
if(img.exists()) {
- it.imic.setImageURI(Uri.fromFile(img))
+ withContext(Dispatchers.Main) {
+ it.imic.setImageURI(Uri.fromFile(img))
+ }
} else {
- it.imic.setImageResource(R.drawable.img_defmask)
+ withContext(Dispatchers.Main) {
+ it.imic.setImageResource(R.drawable.img_defmask)
+ }
}
}
- if(card.isFinish) it.sgnic.visibility = View.VISIBLE
- if(card.isNew) it.sgnnew.visibility = View.VISIBLE
- initClickListeners?.prepareListeners(card, card.name, card.path, card.chapterUUID, card.pageNumber)
- rows[card.index % 20]?.ltbtn?.addView(it)
- it.layoutParams?.height = cardHeight
- it.layoutParams?.width = cardWidth
+ withContext(Dispatchers.Main) {
+ if(card.isFinish) it.sgnic.visibility = View.VISIBLE
+ if(card.isNew) it.sgnnew.visibility = View.VISIBLE
+ initClickListeners?.prepareListeners(card, card.name, card.path, card.chapterUUID, card.pageNumber)
+ rows[card.index % 20]?.ltbtn?.addView(it)
+ it.layoutParams?.height = cardHeight
+ it.layoutParams?.width = cardWidth
+ }
}
}
- interface InitClickListeners{
+ interface InitClickListeners {
fun prepareListeners(v: View, name: String, path: String?, chapterUUID: String?, pn: Int?)
}
-}
\ No newline at end of file
+}
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
index 1d8c55e..02148fc 100644
--- a/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt
+++ b/app/src/main/java/top/fumiama/copymanga/template/ui/InfoCardLoader.kt
@@ -4,15 +4,17 @@ import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.line_lazybooklines.*
+import kotlinx.coroutines.launch
import top.fumiama.copymanga.json.BookListStructure
import top.fumiama.copymanga.json.HistoryBookListStructure
import top.fumiama.copymanga.json.ShelfStructure
import top.fumiama.copymanga.json.TypeBookListStructure
import top.fumiama.copymanga.template.general.MangaPagesFragmentTemplate
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.ui.Navigate
import java.lang.ref.WeakReference
@@ -20,18 +22,12 @@ import java.lang.ref.WeakReference
open 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) {
var offset = 0
private val subUrl get() = getApiUrl()
- var ad: AutoDownloadThread? = null
+ var ad: PausableDownloader? = null
- override fun addPage(){
+ override fun addPage() {
super.addPage()
- ad = AutoDownloadThread(subUrl) { data ->
- if (data == null) {
- activity?.runOnUiThread {
- findNavController().popBackStack()
- }
- return@AutoDownloadThread
- }
- if(isRefresh){
+ ad = PausableDownloader(subUrl) { data ->
+ if(isRefresh) {
page = 0
isRefresh = false
}
@@ -42,7 +38,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
if(results.offset < results.total) {
if(code == 200) {
results.list.forEach { book ->
- if(ad?.exit == true) return@AutoDownloadThread
+ if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(
book?.comic?.name?:"null", null, book?.comic?.cover,
book?.comic?.path_word, null, null,
@@ -61,9 +57,9 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
- if(ad?.exit == true) return@AutoDownloadThread
+ if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(
- book?.comic?.name?:"null", "\n最新${book?.last_chapter_name}", book?.comic?.cover,
+ book?.comic?.name?:"null", "\n云读至${book?.last_chapter_name}", book?.comic?.cover,
book?.comic?.path_word, null, null,
book?.comic?.status==1
)
@@ -80,7 +76,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
- if(ad?.exit == true) return@AutoDownloadThread
+ if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(
book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover,
book?.comic?.path_word, null, null,
@@ -100,7 +96,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
if(results.offset < results.total) {
if(code == 200) {
results?.list?.forEach{ book ->
- if(ad?.exit == true) return@AutoDownloadThread
+ if(ad?.exit == true) return@PausableDownloader
cardList?.addCard(book?.name?:"null", null, book?.cover, book?.path_word, null, null, false)
}
offset += results.list.size
@@ -111,7 +107,16 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
}
onLoadFinish()
}
- ad?.start()
+ lifecycleScope.launch {
+ try {
+ ad?.run()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ try {
+ findNavController().popBackStack()
+ } catch (_: Exception) {}
+ }
+ }
}
override fun initCardList(weakReference: WeakReference) {
super.initCardList(weakReference)
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
index 904e2ab..badbb0a 100644
--- a/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt
+++ b/app/src/main/java/top/fumiama/copymanga/tools/api/CMApi.kt
@@ -1,31 +1,44 @@
package top.fumiama.copymanga.tools.api
-import android.util.Base64
import androidx.preference.PreferenceManager
import com.bumptech.glide.load.model.LazyHeaders
-import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.MainActivity
-import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.http.Proxy
import top.fumiama.copymanga.tools.http.Resolution
+import top.fumiama.dmzj.copymanga.R
import java.io.File
-import java.net.URLEncoder
object CMApi {
- var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null
+ var proxy = if (Proxy.useImageProxy) Proxy(
+ R.string.imgProxyApiUrl,
+ R.string.imgProxyApiRegex,
+ R.string.imgProxyKeyID
+ ) else null
var resolution = Resolution(Regex("c\\d+x\\."))
var myGlideHeaders: LazyHeaders? = null
get() {
MainActivity.mainWeakReference?.get()?.let {
PreferenceManager.getDefaultSharedPreferences(it).apply {
- if(field === null)
+ if (field === null)
field = LazyHeaders.Builder()
- .addHeader("referer", MainActivity.mainWeakReference?.get()?.getString(R.string.referer)!!)
- .addHeader("User-Agent", MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)!!)
+ .addHeader(
+ "referer",
+ MainActivity.mainWeakReference?.get()?.getString(R.string.referer)!!
+ )
+ .addHeader(
+ "User-Agent",
+ MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)!!
+ )
.addHeader("source", "copyApp")
.addHeader("webp", "1")
- .addHeader("version", MainActivity.mainWeakReference?.get()?.getString(R.string.app_ver)!!)
- .addHeader("region", if(!getBoolean("settings_cat_net", false)) "1" else "0")
+ .addHeader(
+ "version",
+ MainActivity.mainWeakReference?.get()?.getString(R.string.app_ver)!!
+ )
+ .addHeader(
+ "region",
+ if (!getBoolean("settings_cat_net", false)) "1" else "0"
+ )
.addHeader("platform", "3")
.build()
}
@@ -34,11 +47,11 @@ object CMApi {
}
var myHostApiUrl: String = ""
get() {
- if(field != "") return field
+ if (field != "") return field
MainActivity.mainWeakReference?.get()?.let {
PreferenceManager.getDefaultSharedPreferences(it).apply {
getString("settings_cat_net_et_api_url", "")?.let { host ->
- if(host != "") {
+ if (host != "") {
field = host
return host
}
@@ -49,25 +62,14 @@ object CMApi {
return field
}
- fun getZipFile(exDir: File?, manga: String, caption: CharSequence, name: CharSequence) = File(exDir, "$manga/$caption/$name.zip")
+ fun getZipFile(exDir: File?, manga: String, caption: CharSequence, name: CharSequence) =
+ File(exDir, "$manga/$caption/$name.zip")
+
fun getChapterInfoApiUrl(arg1: String?, arg2: String?) =
- MainActivity.mainWeakReference?.get()?.getString(R.string.chapterInfoApiUrl)?.format(myHostApiUrl, arg1, arg2)
+ MainActivity.mainWeakReference?.get()?.getString(R.string.chapterInfoApiUrl)
+ ?.format(myHostApiUrl, arg1, arg2)
+
fun getGroupInfoApiUrl(arg1: String?, arg2: String?, arg3: Int? = 0) =
- MainActivity.mainWeakReference?.get()?.getString(R.string.groupInfoApiUrl)?.format(myHostApiUrl, arg1, arg2, arg3)
- fun getLoginConnection(username: String, pwd: String, salt: Int) =
- MainActivity.mainWeakReference?.get()?.getString(R.string.loginApiUrl)?.format(myHostApiUrl)?.let {
- DownloadTools.getConnection(it, "POST")?.apply {
- MainActivity.mainWeakReference?.get()?.let {
- PreferenceManager.getDefaultSharedPreferences(it).apply {
- doOutput = true
- setRequestProperty("content-type", "application/x-www-form-urlencoded;charset=utf-8")
- setRequestProperty("platform", "3")
- setRequestProperty("accept", "application/json")
- val r = if(!getBoolean("settings_cat_net_sw_use_foreign", false)) "1" else "0"
- val pwdb64 = Base64.encode("$pwd-$salt".toByteArray(), Base64.DEFAULT).decodeToString()
- 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())
- }
- }
- }
- }
- }
+ MainActivity.mainWeakReference?.get()?.getString(R.string.groupInfoApiUrl)
+ ?.format(myHostApiUrl, arg1, arg2, arg3)
+}
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 c8eba27..0bf22a0 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
@@ -9,6 +9,7 @@ import java.util.zip.CRC32
import java.util.zip.CheckedOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
+import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
import kotlin.random.Random
@@ -33,15 +34,7 @@ class DownloadPool(folder: String) {
}
operator fun plusAssign(quest: Quest) {
- packZipFile(quest.fileName, quest.imgUrl, quest.refer)
- }
-
- operator fun plusAssign(quests: Array) {
- Thread{
- quests.forEach { quest ->
- packZipFile(quest.fileName, quest.imgUrl, quest.refer)
- }
- }.start()
+ packZipFile(quest.fileName, quest.imgUrl)
}
fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) {
@@ -52,8 +45,8 @@ class DownloadPool(folder: String) {
mOnPageDownloadListener = onPageDownloadListener
}
- private fun packZipFile(fileName: String, imgUrls: Array, refer: String?) {
- Thread{
+ 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
@@ -61,9 +54,9 @@ class DownloadPool(folder: String) {
if(f.exists()) {
try {
val zipFile = ZipFile(f)
- start = zipFile.size() - 1
+ start = zipFile.size()
zipFile.close()
- Log.d("MyDP", "last downloaded index: $start")
+ Log.d("MyDP", "next download index: $start")
if (start <= 0 || start >= imgUrls.size) { // error or re-download
f.delete()
f.createNewFile()
@@ -75,8 +68,25 @@ class DownloadPool(folder: String) {
f.createNewFile()
}
} else f.createNewFile()
- val zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f, true), CRC32()))
- zip.setLevel(9)
+ 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 {
@@ -93,7 +103,9 @@ class DownloadPool(folder: String) {
zip.closeEntry()
true
}?:false
+ if(exit) break
if (!s) sleep(2000)
+ if(exit) break
}
if(!s && tryTimes <= 0) {
succeed = false
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 3d7d06c..94cea10 100644
--- a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt
+++ b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadTools.kt
@@ -3,7 +3,8 @@ package top.fumiama.copymanga.tools.http
import android.content.Context
import android.util.Log
import androidx.preference.PreferenceManager
-import okhttp3.RequestBody
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity
import top.fumiama.dmzj.copymanga.R
import java.net.HttpURLConnection
@@ -12,12 +13,12 @@ import java.util.concurrent.Callable
import java.util.concurrent.FutureTask
object DownloadTools {
- fun getConnection(url: String?, method: String = "GET", refer: String? = null, ua: String? = null) =
- url?.let {
+ fun getApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null, timeout: Int = 20000) =
+ url.let {
val connection = URL(url).openConnection() as HttpURLConnection
connection.requestMethod = method
- connection.connectTimeout = 20000
- connection.readTimeout = 20000
+ connection.connectTimeout = timeout
+ connection.readTimeout = timeout
connection.apply {
setRequestProperty("host", url.substringAfter("://").substringBefore("/"))
ua?.let { setRequestProperty("user-agent", it) }
@@ -37,44 +38,31 @@ object DownloadTools {
}
setRequestProperty("platform", "3")
}
- Log.d("Mydl", "getHttp: ${connection.requestProperties.map { "${it.key}: ${it.value}" }.joinToString("\n")}")
+ Log.d("Mydl", "getConnection: ${connection.requestProperties.map { "${it.key}: ${it.value}" }.joinToString("\n")}")
connection
}
- private fun getNormalConnection(url: String?, method: String = "GET", ua: String? = null) =
- url?.let {
+ private fun getNormalConnection(url: String, method: String = "GET", ua: String? = null, timeout: Int = 20000) =
+ url.let {
val connection = URL(url).openConnection() as HttpURLConnection
connection.requestMethod = method
- connection.connectTimeout = 20000
- connection.readTimeout = 20000
+ connection.connectTimeout = timeout
+ connection.readTimeout = timeout
connection.apply {
setRequestProperty("host", url.substringAfter("://").substringBefore("/"))
ua?.let { setRequestProperty("user-agent", it) }
}
}
- fun getHttpContent(u: String, refer: String? = null, ua: String? = null): ByteArray? {
- Log.d("Mydl", "getHttp: $u")
- var ret: ByteArray? = null
- val task = FutureTask(Callable {
- try {
- getConnection(u, "GET", refer, ua)?.apply {
- ret = inputStream.readBytes()
- disconnect()
- }
- } catch (ex: Exception) {
- ex.printStackTrace()
+ suspend fun getHttpContent(u: String, refer: String? = null, ua: String? = null): ByteArray =
+ withContext(Dispatchers.IO) {
+ getApiConnection(u, "GET", refer, ua).let {
+ val ret = it.inputStream.readBytes()
+ it.disconnect()
+ Log.d("Mydl", "getHttpContent: ${ret.size} bytes")
+ ret
}
- return@Callable ret
- })
- Thread(task).start()
- return try {
- task.get()
- } catch (ex: Exception) {
- ex.printStackTrace()
- null
}
- }
fun getHttpContent(u: String, readSize: Int): ByteArray? {
Log.d("Mydl", "getHttp: $u")
@@ -82,13 +70,13 @@ object DownloadTools {
val task = FutureTask(Callable {
try {
val connection = getNormalConnection(u, "GET")
- val ci = connection?.inputStream
+ val ci = connection.inputStream
if(readSize > 0) {
ret = ByteArray(readSize)
ci?.read(ret, 0, readSize)
} else ret = ci?.readBytes()
ci?.close()
- connection?.disconnect()
+ connection.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
@@ -103,7 +91,7 @@ object DownloadTools {
}
}
- fun touch(url: String?): FutureTask? =
+ /*fun touch(url: String?): FutureTask? =
url?.let {
Log.d("Mydl", "touchHttp: $it")
var ret: ByteArray? = null
@@ -122,7 +110,7 @@ object DownloadTools {
})
Thread(task).start()
task
- }
+ }*/
fun prepare(url: String?): FutureTask? =
url?.let {
@@ -156,7 +144,7 @@ object DownloadTools {
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
- getConnection(url, method, refer, ua)?.apply {
+ getApiConnection(url, method, refer, ua)?.apply {
outputStream.write(body)
ret = inputStream.readBytes()
disconnect()
diff --git a/app/src/main/java/top/fumiama/copymanga/tools/http/Proxy.kt b/app/src/main/java/top/fumiama/copymanga/tools/http/Proxy.kt
index 9b80b76..ea0d5d8 100644
--- a/app/src/main/java/top/fumiama/copymanga/tools/http/Proxy.kt
+++ b/app/src/main/java/top/fumiama/copymanga/tools/http/Proxy.kt
@@ -6,21 +6,28 @@ import top.fumiama.copymanga.MainActivity
import java.net.URLEncoder
import java.nio.charset.Charset
-class Proxy(id: Int, apiPrefixID: Int, keyID: Int? = null) {
+class Proxy(id: Int, apiRegexID: Int, keyID: Int? = null) {
private val code = keyID?.let { k ->
MainActivity.mainWeakReference?.get()?.let {
PreferenceManager.getDefaultSharedPreferences(it).getString(it.getString(k), null)
}
}
private val proxyApiUrl = MainActivity.mainWeakReference?.get()?.getString(id)
- private val apiPrefix = MainActivity.mainWeakReference?.get()?.getString(apiPrefixID)?:""
+ private val apiRegex = Regex(MainActivity.mainWeakReference?.get()?.getString(apiRegexID)?:"")
fun wrap(u: String): String {
- if(!u.startsWith(apiPrefix)) return u
- if(code != null) {
- return proxyApiUrl?.format(code, URLEncoder.encode(u, Charset.defaultCharset().name()))?:u
+ if(!apiRegex.matches(u)) {
+ Log.d("MyP", "[N] wrap: $u")
+ return u
}
- return proxyApiUrl?.format(URLEncoder.encode(u, Charset.defaultCharset().name()))?:u
+ if(!code.isNullOrEmpty()) {
+ val wu = proxyApiUrl?.format(code, URLEncoder.encode(u, Charset.defaultCharset().name()))?:u
+ Log.d("MyP", "[M] wrap: $wu")
+ return wu
+ }
+ Log.d("MyP", "[C] wrap: $u")
+ //return proxyApiUrl?.format(URLEncoder.encode(u, Charset.defaultCharset().name()))?:u
+ return u
}
companion object {
diff --git a/app/src/main/java/top/fumiama/copymanga/tools/thread/TimeThread.kt b/app/src/main/java/top/fumiama/copymanga/tools/thread/TimeThread.kt
index 5d29f1b..ac755a8 100644
--- a/app/src/main/java/top/fumiama/copymanga/tools/thread/TimeThread.kt
+++ b/app/src/main/java/top/fumiama/copymanga/tools/thread/TimeThread.kt
@@ -2,13 +2,13 @@ package top.fumiama.copymanga.tools.thread
import android.os.Handler
-class TimeThread(private val handler: Handler, private val msg: Int) : Thread() {
+class TimeThread(private val handler: Handler, private val msg: Int, private val interval: Long = 3000) : Thread() {
var canDo = false
override fun run() {
while (canDo) {
try {
handler.sendEmptyMessage(msg)
- sleep(3000)
+ sleep(interval)
} catch (e: InterruptedException) {
e.printStackTrace()
}
diff --git a/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt b/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt
index 4d9eec4..d0b57c0 100644
--- a/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt
+++ b/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt
@@ -8,6 +8,8 @@ import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.view.View
import android.widget.Toast
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
import top.fumiama.dmzj.copymanga.R
import java.lang.ref.WeakReference
import kotlin.math.sqrt
@@ -39,11 +41,11 @@ class UITools(that: Context?, w: WeakReference? = null) {
}
} ?: transportStringError
}
- fun toastError(s: String, willFinish: Boolean = true) {
+ suspend fun toastError(s: String, willFinish: Boolean = true) = withContext(Dispatchers.Main) {
Toast.makeText(zis, s, Toast.LENGTH_SHORT).show()
if (willFinish) weak?.get()?.finish()
}
- fun toastError(s: Int, willFinish: Boolean = true) {
+ suspend fun toastError(s: Int, willFinish: Boolean = true) = withContext(Dispatchers.Main) {
Toast.makeText(zis, s, Toast.LENGTH_SHORT).show()
if (willFinish) weak?.get()?.finish()
}
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 b73fa00..3c6060c 100644
--- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt
+++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt
@@ -27,6 +27,7 @@ import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.Thread.sleep
import java.lang.ref.WeakReference
+import java.util.concurrent.atomic.AtomicReference
class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
var isOnPause = false
@@ -65,7 +66,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
mBookHandler = BookHandler(WeakReference(this), path)
Log.d("MyBF", "read path: $path")
- bookHandler = mBookHandler
+ bookHandler.set(mBookHandler)
lifecycleScope.launch {
withContext(Dispatchers.IO) {
sleep(600)
@@ -73,14 +74,14 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
}
} else {
- bookHandler = mBookHandler
+ bookHandler.set(mBookHandler)
}
}
override fun onResume() {
super.onResume()
isOnPause = false
- bookHandler = mBookHandler
+ bookHandler.set(mBookHandler)
activity?.apply {
toolbar.title = mBookHandler?.book?.results?.comic?.name
}
@@ -98,7 +99,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
mBookHandler?.ads?.forEach {
it.exit = true
}
- bookHandler = null
+ bookHandler.set(null)
}
fun setStartRead() {
@@ -126,12 +127,14 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
fun setAddToShelf() {
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}")
- tic.text = b?.results?.browse?.chapter_name?.let { name ->
- getString(R.string.text_format_cloud_read_to).format(name)
+ MainActivity.shelf?.query(mBookHandler?.path!!)?.let { b ->
+ mBookHandler?.collect = b.results?.collect?:-2
+ Log.d("MyBF", "get collect of ${mBookHandler?.path} = ${mBookHandler?.collect}")
+ 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) {
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
@@ -162,12 +165,13 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
}
- fun navigate2dl(){
+ fun navigate2dl() {
val bundle = Bundle()
+ Log.d("MyBF", "nav2: ${arguments?.getString("path")?:"null"}")
bundle.putString("path", arguments?.getString("path")?:"null")
bundle.putString("name", mBookHandler!!.book?.results?.comic?.name)
- if(mBookHandler!!.vols != null) {
- bundle.putBoolean("loadJson", true)
+ if(mBookHandler!!.vols != null && mBookHandler!!.json != null) {
+ bundle.putString("loadJson", mBookHandler!!.json)
}
bundle.putStringArray("group", mBookHandler!!.gpws)
bundle.putStringArray("groupNames", mBookHandler!!.keys)
@@ -178,6 +182,6 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
}
companion object {
- var bookHandler: BookHandler? = null
+ var bookHandler: AtomicReference = AtomicReference(null)
}
-}
\ No newline at end of file
+}
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 5317835..f7e5dbf 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
@@ -2,7 +2,6 @@ package top.fumiama.copymanga.ui.book
import android.graphics.Bitmap
import android.os.Bundle
-import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
@@ -12,6 +11,7 @@ import android.widget.TextView
import android.widget.Toast
import androidx.core.graphics.drawable.toBitmap
import androidx.core.widget.NestedScrollView
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
@@ -28,6 +28,9 @@ 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 kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.json.BookInfoStructure
import top.fumiama.copymanga.json.ChapterStructure
@@ -35,7 +38,7 @@ import top.fumiama.copymanga.json.ThemeStructure
import top.fumiama.copymanga.json.VolumeStructure
import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.template.http.AutoDownloadHandler
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideBlurTransformation
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
@@ -51,7 +54,7 @@ import java.lang.ref.WeakReference
class BookHandler(private val th: WeakReference, val path: String)
: AutoDownloadHandler(th.get()?.getString(R.string.bookInfoApiUrl)?.format(CMApi.myHostApiUrl, path)?: "",
BookInfoStructure::class.java,
- Looper.myLooper()!!){
+ th.get()){
private val that get() = th.get()
private var hasToastedError = false
get(){
@@ -61,13 +64,14 @@ class BookHandler(private val th: WeakReference, val path: String)
}
var book: BookInfoStructure? = null
private var complete = false
- var ads = emptyArray()
+ var ads = emptyArray()
var gpws = arrayOf()
var keys = arrayOf()
var cnts = intArrayOf()
var vols: Array? = null
var chapterNames = arrayOf()
var collect: Int = -1
+ var json: String? = null
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.lbl, false)
var urlArray = arrayOf()
@@ -87,7 +91,7 @@ class BookHandler(private val th: WeakReference, val path: String)
override fun onError() {
super.onError()
if(exit) return
- if(!hasToastedError) that?.activity?.runOnUiThread {
+ if(!hasToastedError) /*that?.activity?.runOnUiThread*/ {
Toast.makeText(that?.context, R.string.null_book, Toast.LENGTH_SHORT).show()
that?.apply { findNavController().popBackStack() }
}
@@ -100,10 +104,11 @@ class BookHandler(private val th: WeakReference, val path: String)
}
override fun getGsonItem() = book
- override fun doWhenFinishDownload() {
+ override suspend fun doWhenFinishDownload() = withContext(Dispatchers.IO) {
super.doWhenFinishDownload()
- if(exit) return
- if(keys.isEmpty()) book?.results?.groups?.values?.forEach{
+ if(exit) return@withContext
+
+ if(keys.isEmpty()) book?.results?.groups?.values?.forEach {
keys += it.name
gpws += it.path_word
if (it.count == 0) {
@@ -245,14 +250,12 @@ class BookHandler(private val th: WeakReference, val path: String)
}
}
- private fun addVolumesView(l: LinearLayout, v: View) {
- that?.activity?.runOnUiThread {
- l.addView(v)
- }
+ private suspend fun addVolumesView(l: LinearLayout, v: View) = withContext(Dispatchers.Main) {
+ l.addView(v)
}
- private fun setVolume(fbl: LinearLayout, p: Int) = Thread {
- if (exit) return@Thread
+ private suspend fun setVolume(fbl: LinearLayout, p: Int) = withContext(Dispatchers.IO) {
+ if (exit) return@withContext
that?.apply {
book?.results?.apply {
var i = 0
@@ -261,16 +264,16 @@ class BookHandler(private val th: WeakReference, val path: String)
}
var last = i-1
vols?.get(p)?.let { v ->
- if(exit) return@Thread
+ if(exit) return@withContext
var line: View? = null
last += v.results.list.size
v.results.list.forEach {
val f = CMApi.getZipFile(context?.getExternalFilesDir(""), comic.name, keys[p], it.name)
- Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}")
+ //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)
- if (exit) return@Thread
- }?:return@Thread
+ while (isOnPause && !exit) sleep(100)
+ if (exit) return@withContext
+ }?:return@withContext
if(line == null) {
if(i == last) {
line = layoutInflater.inflate(R.layout.line_chapter, fbl, false)
@@ -304,10 +307,10 @@ class BookHandler(private val th: WeakReference, val path: String)
}
}
}
- }.start()
+ }
- private fun setViewManga() = Thread {
- if (exit) return@Thread
+ private suspend fun setViewManga() = withContext(Dispatchers.IO) {
+ if (exit) return@withContext
that?.apply {
book?.results?.apply {
ViewMangaActivity.fileArray = arrayOf()
@@ -316,7 +319,7 @@ class BookHandler(private val th: WeakReference, val path: String)
var i = 0
var last = -1
vols?.forEachIndexed { groupIndex, v ->
- if(exit) return@Thread
+ if(exit) return@withContext
last += v.results.list.size
v.results.list.forEach {
urlArray += CMApi.getChapterInfoApiUrl(
@@ -328,16 +331,16 @@ class BookHandler(private val th: WeakReference, val path: String)
chapterNames += it.name
ViewMangaActivity.uuidArray += it.uuid
that?.isOnPause?.let { isOnPause ->
- while (isOnPause && !exit) sleep(1000)
- if (exit) return@Thread
- }?:return@Thread
+ while (isOnPause && !exit) sleep(100)
+ if (exit) return@withContext
+ }?:return@withContext
i++
}
}
}
}
sendEmptyMessage(9) // end set layout
- }.start()
+ }
private fun loadVolume(name: String, path: String, nav: Int){
if(complete) {
@@ -349,7 +352,7 @@ class BookHandler(private val th: WeakReference, val path: String)
}
}
- private fun initComicData() = Thread {
+ private suspend fun initComicData() = withContext(Dispatchers.IO) withIO@ {
var volumes = emptyArray()
val counts = cnts.clone()
gpws.forEachIndexed { i, gpw ->
@@ -358,49 +361,58 @@ class BookHandler(private val th: WeakReference, val path: String)
val times = counts[i] / 100
val remain = counts[i] % 100
val re = arrayOfNulls(if(remain != 0) (times+1) else (times))
- if (re.isEmpty()) that?.activity?.runOnUiThread {
- Toast.makeText(that?.context, "获取${gpw}失败", Toast.LENGTH_SHORT).show()
- return@runOnUiThread
+ if (re.isEmpty()) {
+ withContext(Dispatchers.Main) {
+ Toast.makeText(that?.context, "获取${gpw}失败", Toast.LENGTH_SHORT).show()
+ }
+ return@forEachIndexed
}
Log.d("MyBFH", "${i}卷共${if(times == 0) 1 else times}次加载")
do {
counts[i] = counts[i] - 100
CMApi.getGroupInfoApiUrl(path, gpw, offset)?.let {
Log.d("MyBFH", "get api: $it")
- if(ComicDlFragment.exit) return@Thread
- val ad = AutoDownloadThread(it) { result ->
- val r = Gson().fromJson(result?.decodeToString(), VolumeStructure::class.java)
- re[r.results.offset / 100] = r
- Log.d("MyBFH", "第${i}卷返回, 大小: ${r.results.list.size}")
- }
- ads += ad
- ad.start()
- offset += 100
- sleep(1000)
- }
- } while (counts[i] > 0)
- var c = 0
- while (c++ < 80) {
- sleep(1000)
- if(ComicDlFragment.exit) return@Thread
- if(re.all { it != null }) break
- }
- if(re.isNotEmpty()) {
- val r = re[0]
- var s = emptyArray()
- re.forEach {
- it?.results?.list?.forEach {
- s += it
+ if(ComicDlFragment.exit) return@withIO
+ val ad = PausableDownloader(it) { result ->
+ try {
+ val r = Gson().fromJson(result.decodeToString(), VolumeStructure::class.java)
+ re[r.results.offset / 100] = r
+ Log.d("MyBFH", "第${i}卷返回, 大小: ${r.results.list.size}")
+ } catch (e: Exception) {
+ e.printStackTrace()
+ that?.findNavController()?.popBackStack()
}
}
- r?.results?.list = s
- r?.apply { volumes += this }
- } else re[0]?.apply { volumes += this }
+ ads += ad
+ ad.run()
+ offset += 100
+ sleep(100)
+ }
+ } while (counts[i] > 0)
+
+ var c = 0
+ while (c++ < 80) {
+ sleep(100)
+ if(ComicDlFragment.exit) return@withIO
+ if(re.all { it != null }) break
+ }
+ if(re.isNotEmpty()) {
+ val r = re[0]
+ var s = emptyArray()
+ re.forEach { v ->
+ v?.results?.list?.forEach {
+ s += it
+ }
+ }
+ r?.results?.list = s
+ r?.apply { volumes += this }
+ } else re[0]?.apply { volumes += this }
}
+
var c = 0
while (c < 80 && volumes.size != gpws.size) {
- sleep(1000)
- if(ComicDlFragment.exit) return@Thread
+ sleep(100)
+ if(ComicDlFragment.exit) return@withIO
Log.d("MyBFH", "已有:${volumes.size} 共:${gpws.size}")
c++
}
@@ -408,7 +420,7 @@ class BookHandler(private val th: WeakReference, val path: String)
saveVolumes(volumes)
that?.fbtab?.let { tab ->
that?.fbvp?.let { vp ->
- that?.activity?.runOnUiThread {
+ withContext(Dispatchers.Main) {
vp.adapter = ViewData(vp).RecyclerViewAdapter()
TabLayoutMediator(tab, vp) { t, p ->
t.text = keys[p]
@@ -418,9 +430,9 @@ class BookHandler(private val th: WeakReference, val path: String)
}
setViewManga()
}
- }.start()
+ }
- private fun saveVolumes(volumes: Array) {
+ private suspend fun saveVolumes(volumes: Array) = withContext(Dispatchers.IO) {
that?.context?.getExternalFilesDir("")?.let { home ->
book?.results?.comic?.name?.let { name ->
val mangaFolder = File(home, name)
@@ -429,27 +441,25 @@ class BookHandler(private val th: WeakReference, val path: String)
File(mangaFolder, "info.json").writeText(json!!)
File(mangaFolder, "grps.json").writeText(Gson().toJson(keys))
that?.apply {
- Thread {
- var cnt = 0
- var success = false
- while (cnt++ < 10 && !success) {
- sleep(1000)
- if (exit) return@Thread
- File(mangaFolder, "head.jpg").let { head ->
- val fo = head.outputStream()
- try {
- imic.drawable.toBitmap().compress(Bitmap.CompressFormat.JPEG, 90, fo)
- success = true
- } catch (e: Exception) {
- e.printStackTrace()
- }
- fo.close()
+ var cnt = 0
+ var success = false
+ while (cnt++ < 10 && !success) {
+ sleep(100)
+ if (exit) return@withContext
+ File(mangaFolder, "head.jpg").let { head ->
+ val fo = head.outputStream()
+ try {
+ imic.drawable.toBitmap().compress(Bitmap.CompressFormat.JPEG, 90, fo)
+ success = true
+ } catch (e: Exception) {
+ e.printStackTrace()
}
+ fo.close()
}
- if (!success) that?.activity?.runOnUiThread {
- Toast.makeText(that?.context, R.string.download_cover_timeout, Toast.LENGTH_SHORT).show()
- }
- }.start()
+ }
+ if (!success) withContext(Dispatchers.Main) {
+ Toast.makeText(that?.context, R.string.download_cover_timeout, Toast.LENGTH_SHORT).show()
+ }
}
}
}
@@ -463,7 +473,7 @@ class BookHandler(private val th: WeakReference, val path: String)
}
override fun onBindViewHolder(holder: ViewData, position: Int) {
- setVolume(holder.itemView.fbl, position)
+ that?.lifecycleScope?.launch { setVolume(holder.itemView.fbl, position) }
}
override fun getItemCount(): Int = keys.size
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
index 426346c..8e61dc6 100644
--- 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
@@ -2,12 +2,17 @@ package top.fumiama.copymanga.ui.cardflow.sort
import android.os.Bundle
import android.view.View
+import androidx.lifecycle.lifecycleScope
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 kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.FilterStructure
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.json.ThemeStructure
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.template.ui.StatusCardFlow
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@@ -36,102 +41,69 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou
override fun setListeners() {
super.setListeners()
- AutoDownloadThread(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) {
- if(ad?.exit == true) return@AutoDownloadThread
- it?.let {
- filter = Gson().fromJson(it.inputStream().reader(), FilterStructure::class.java)
- if(ad?.exit == true) return@AutoDownloadThread
- activity?.runOnUiThread{
- if(ad?.exit != true) setClasses()
+ lifecycleScope.launch {
+ PausableDownloader(getString(R.string.filterApiUrl).format(CMApi.myHostApiUrl)) {
+ if(ad?.exit == true) return@PausableDownloader
+ it.let {
+ filter = Gson().fromJson(it.inputStream().reader(), FilterStructure::class.java)
+ if(ad?.exit == true) return@PausableDownloader
+ withContext(Dispatchers.Main) {
+ if(ad?.exit != true) setClasses()
+ }
}
- }
- }.start()
+ }.run()
+ }
}
- private fun setClasses(){
+ private fun setClasses() {
filter?.results?.top?.let { items ->
- if(ad?.exit == true) return@let
- line_sort_region.apt.text = "全部"
- line_sort_region.setOnClickListener {
- val popupMenu = popupMenu {
- style = R.style.Widget_MPM_Menu_Dark_CustomBackground
- section {
- item {
- label = "全部"
- labelColor = it.apt.currentTextColor
- callback = {
- region = -1
- it.apt.text = "全部"
- Thread{
- sleep(400)
- activity?.runOnUiThread {
- reset()
- addPage()
- }
- }.start()
- }
- }
- for(i in items.indices) item {
- label = items[i].name
- labelColor = it.apt.currentTextColor
- callback = { //optional
- it.apt.text = label
- region = i
- Thread{
- sleep(400)
- activity?.runOnUiThread {
- reset()
- addPage()
- }
- }.start()
- }
- }
- }
- }
- this.context?.let { it1 -> popupMenu.show(it1, it) }
- }
+ setMenu(items, line_sort_region)
}
filter?.results?.theme?.let { items ->
- if(ad?.exit == true) return@let
- line_sort_class.apt.text = "全部"
- line_sort_class.setOnClickListener {
- val popupMenu = popupMenu {
- style = R.style.Widget_MPM_Menu_Dark_CustomBackground
- section {
- item {
- label = "全部"
- labelColor = it.apt.currentTextColor
- callback = {
- theme = -1
- it.apt.text = "全部"
- Thread{
- sleep(400)
- activity?.runOnUiThread {
- reset()
- addPage()
- }
- }.start()
- }
- }
- for(i in items.indices) item {
- label = items[i].name
- labelColor = it.apt.currentTextColor
- callback = { //optional
- it.apt.text = label
- theme = i
- Thread{
- sleep(400)
- activity?.runOnUiThread {
- reset()
- addPage()
- }
- }.start()
- }
- }
- }
+ setMenu(items, line_sort_class)
+ }
+ }
+
+ private fun suspendReset() {
+ lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ sleep(400)
+ withContext(Dispatchers.Main) {
+ reset()
+ addPage()
}
- this.context?.let { it1 -> popupMenu.show(it1, it) }
}
}
}
-}
\ No newline at end of file
+
+ private fun setMenu(items: Array, line: View) {
+ if(ad?.exit == true) return
+ line.apt.text = "全部"
+ line.setOnClickListener {
+ val popupMenu = popupMenu {
+ style = R.style.Widget_MPM_Menu_Dark_CustomBackground
+ section {
+ item {
+ label = "全部"
+ labelColor = it.apt.currentTextColor
+ callback = {
+ region = -1
+ it.apt.text = "全部"
+ suspendReset()
+ }
+ }
+ for(i in items.indices) item {
+ label = items[i].name
+ labelColor = it.apt.currentTextColor
+ callback = { //optional
+ it.apt.text = label
+ region = i
+ suspendReset()
+ }
+ }
+ }
+ }
+ context?.let { c -> popupMenu.show(c, it) }
+ }
+ }
+}
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
index 0e5bcad..3b24688 100644
--- 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
@@ -1,11 +1,15 @@
package top.fumiama.copymanga.ui.cardflow.topic
import android.os.Bundle
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.fragment_topic.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.TopicStructure
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@@ -18,23 +22,27 @@ class TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_to
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- AutoDownloadThread(getString(R.string.topicApiUrl).format(CMApi.myHostApiUrl, arguments?.getString("path"))) { data ->
- if(ad?.exit == true) return@AutoDownloadThread
- data?.apply {
- val r = inputStream().reader()
- Gson().fromJson(r, TopicStructure::class.java)?.apply {
- if(ad?.exit == true) return@AutoDownloadThread
- activity?.let {
- it.runOnUiThread {
- if(ad?.exit == true) return@runOnUiThread
- it.toolbar.title = results.title
- ftttime.text = results.datetime_created
- fttintro.text = results.intro
- type = results.type
+ lifecycleScope.launch {
+ PausableDownloader(getString(R.string.topicApiUrl).format(CMApi.myHostApiUrl, arguments?.getString("path"))) { data ->
+ withContext(Dispatchers.IO) {
+ if(ad?.exit == true) return@withContext
+ data.apply {
+ val r = inputStream().reader()
+ Gson().fromJson(r, TopicStructure::class.java)?.apply {
+ if(ad?.exit == true) return@withContext
+ activity?.let {
+ withContext(Dispatchers.Main) withMain@ {
+ if(ad?.exit == true) return@withMain
+ it.toolbar.title = results.title
+ ftttime.text = results.datetime_created
+ fttintro.text = results.intro
+ type = results.type
+ }
+ }
}
}
}
- }
- }.start()
+ }.run()
+ }
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt
index a2fff93..448e092 100644
--- a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt
+++ b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlFragment.kt
@@ -4,11 +4,17 @@ import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.View
+import android.widget.Toast
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
import com.google.gson.Gson
import kotlinx.android.synthetic.main.fragment_dlcomic.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.ChapterStructure
import top.fumiama.copymanga.json.VolumeStructure
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.template.general.NoBackRefreshFragment
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.dmzj.copymanga.R
@@ -18,29 +24,31 @@ import java.lang.ref.WeakReference
class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
var ltbtn: View? = null
- var ads = emptyArray()
+ private var ads = emptyArray()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exit = false
ldwn?.setPadding(0, 0, 0, navBarHeight)
- if(isFirstInflate){
- when {
- arguments?.getBoolean("callFromOldDL", false) == true -> initOldComicData()
- arguments?.getBoolean("loadJson", false) == true -> context?.getExternalFilesDir("")?.let { home ->
- arguments?.getString("name")?.let {
- Thread{
+ if(isFirstInflate) lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ when {
+ arguments?.getBoolean("callFromOldDL", false) == true -> initOldComicData()
+ arguments?.containsKey("loadJson") == true -> context?.getExternalFilesDir("")?.let { home ->
+ arguments?.getString("name")?.let {
sleep(600)
- activity?.runOnUiThread {
- start2load(loadFromJson(), true, loadGroupsFromFile(File(home, "$it/grps.json")))
- }
- }.start()
+ Log.d("MyCDF", "loadJson by arguments")
+ start2load(
+ loadFromJson(arguments?.getString("loadJson")!!),
+ true, loadGroupsFromFile(File(home, "$it/grps.json"))
+ )
+ }
}
+ else -> initComicData(
+ arguments?.getString("path"),
+ arguments?.getStringArray("group"),
+ arguments?.getIntArray("count")
+ )
}
- else -> initComicData(
- arguments?.getString("path"),
- arguments?.getStringArray("group"),
- arguments?.getIntArray("count")
- )
}
}
}
@@ -58,13 +66,14 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
handler = null
}
- private fun start2load(volumes: Array, isFromFile: Boolean = false, groupArray: Array? =null){
- handler = ComicDlHandler(Looper.myLooper()!!,
- WeakReference(this),
- volumes,
- arguments?.getString("name")?:"null",
- if(isFromFile) groupArray else arguments?.getStringArray("groupNames"))
- if(!isFromFile) Thread{
+ private suspend fun start2load(volumes: Array, isFromFile: Boolean = false, groupArray: Array? =null) = withContext(Dispatchers.IO) {
+ withContext(Dispatchers.Main) {
+ handler = ComicDlHandler(Looper.myLooper()!!, WeakReference(this@ComicDlFragment),
+ volumes, arguments?.getString("name")?:"null",
+ if(isFromFile) groupArray else arguments?.getStringArray("groupNames")
+ )
+ }
+ if(!isFromFile) {
context?.getExternalFilesDir("")?.let { home ->
arguments?.getString("name")?.let { name ->
val mangaFolder = File(home, name)
@@ -75,18 +84,18 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
}
}
}
- }.start()
+ }
handler?.startLoad()
}
- private fun loadFromJson() = Gson().fromJson(json, Array::class.java)
+ private fun loadFromJson(json: String) = Gson().fromJson(json, Array::class.java)
private fun loadGroupsFromFile(file: File) = Gson().fromJson(file.reader(), Array::class.java)
/*private fun setMenuInvisible(menu: Menu){
menu.findItem(R.id.action_download)?.isVisible = false
}*/
- private fun initComicData(pw: String?, gpws: Array?, counts: IntArray?) = Thread {
+ private suspend fun initComicData(pw: String?, gpws: Array?, counts: IntArray?) = withContext(Dispatchers.IO) {
var volumes = emptyArray()
if (gpws != null) {
gpws.forEachIndexed { i, gpw ->
@@ -99,21 +108,29 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
do {
counts?.set(i, counts[i] - 100)
CMApi.getGroupInfoApiUrl(pw, gpw, offset)?.let {
- if(exit) return@Thread
- val ad = AutoDownloadThread(it) { result ->
+ if(exit) return@withContext
+ val ad = PausableDownloader(it) { result ->
Log.d("MyCDF", "第${i}卷返回")
- val r = Gson().fromJson(result?.decodeToString(), VolumeStructure::class.java)
+ val r = Gson().fromJson(result.decodeToString(), VolumeStructure::class.java)
re[r.results.offset / 100] = r
}
ads += ad
- ad.start()
+ try {
+ ad.run()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ withContext(Dispatchers.Main) {
+ Toast.makeText(context, "加载${gpw}第${i}部分失败", Toast.LENGTH_SHORT).show()
+ findNavController().popBackStack()
+ }
+ }
offset += 100
}
} while ((counts?.get(i) ?: 0) > 0)
var c = 0
while (c++ < 80) {
sleep(1000)
- if(exit) return@Thread
+ if(exit) return@withContext
if(re.all { it != null }) break
}
if(re.size > 1) {
@@ -131,21 +148,18 @@ class ComicDlFragment: NoBackRefreshFragment(R.layout.fragment_dlcomic) {
var c = 0
while (c < 80 && volumes.size != gpws.size) {
sleep(1000)
- if(exit) return@Thread
+ if(exit) return@withContext
Log.d("MyCDF", "已有:${volumes.size} 共:${gpws.size}")
c++
}
if (volumes.size == gpws.size) {
- activity?.runOnUiThread {
- start2load(volumes)
- }
+ start2load(volumes)
}
}
- }.start()
+ }
- private fun initOldComicData() {
- handler = ComicDlHandler(Looper.myLooper()!!,
- WeakReference(this),
+ private suspend fun initOldComicData() = withContext(Dispatchers.IO) {
+ handler = ComicDlHandler(Looper.myLooper()!!, WeakReference(this@ComicDlFragment),
arguments?.getString("name")?:"null")
handler?.startLoad()
}
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 6305acf..353385d 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
@@ -11,6 +11,7 @@ import android.util.Log
import android.view.ViewGroup
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.*
@@ -20,8 +21,12 @@ 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.line_caption.view.*
+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
@@ -92,41 +97,35 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference that?.tdwn?.text = "${dldChapter}/${checkedChapter}"
- 7 -> deleteChapters(msg.obj as File, msg.arg1)
+ 7 -> that?.lifecycleScope?.launch { deleteChapters(msg.obj as File, msg.arg1) }
9 -> that?.cdwn?.setCardBackgroundColor(that!!.resources.getColor(R.color.colorGreen))
- 10 -> addTbtn(msg.obj as Array)
- 11 -> addCaption(msg.obj as String)
- 12 -> addDiv()
+ //10 -> addButton(msg.obj as Array)
+ //11 -> addCaption(msg.obj as String)
+ //12 -> addDiv()
13 -> if(complete) showMultiSelectInfo()
}
}
- fun startLoad(){
+ suspend fun startLoad() = withContext(Dispatchers.IO) {
setComponents()
if(isOld) analyzeOldStructure()
- else Thread{
+ else {
urlArray = arrayOf()
ViewMangaActivity.fileArray = arrayOf()
ViewMangaActivity.uuidArray = arrayOf()
vols.forEachIndexed { i, vol ->
val caption = groupNames?.get(i)?:vol.results.list[0].group_path_word
Log.d("MyCDH", "caption: $caption, group name: ${groupNames?.get(i)}")
- obtainMessage(11, caption).sendToTarget() //addCaption
- vol.results.list.forEach { chapter ->
- var data = arrayOf()
- data += chapter.name
- data += chapter.uuid
- data += caption
- data += CMApi.getChapterInfoApiUrl(chapter.comic_path_word, chapter.uuid)?:""
- obtainMessage(10, data).sendToTarget()
+ withContext(Dispatchers.Main) {
+ addCaption(caption) {
+ addButtons(vol.results.list, caption)
+ }
}
- sendEmptyMessage(12) //addDiv
}
complete = true
- }.start()
-
+ }
}
- private fun addDiv(){
+ private suspend fun addDiv() = withContext(Dispatchers.Main) {
that?.ldwn?.addView(
that!!.layoutInflater.inflate(R.layout.div_h, that!!.ldwn, false),
ViewGroup.LayoutParams(
@@ -135,7 +134,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference Unit) = withContext(Dispatchers.Main) {
val tc = that?.layoutInflater?.inflate(R.layout.line_caption, that!!.ldwn, false)
tc?.tcptn?.text = title
that?.ldwn?.addView(
@@ -147,13 +146,16 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference
if(i.isChecked) {
+ withContext(Dispatchers.Main) {
+ i.isEnabled = false
+ }
i.url?.let {
- mangaDlTools.downloadChapterInVol(
- it,
- i.chapterName,
- i.caption?:"null",
- i.index
- )
+ Thread {
+ that?.lifecycleScope?.launch {
+ mangaDlTools.downloadChapterInVol(
+ it,
+ i.chapterName,
+ i.caption?:"null",
+ i.index
+ )
+ }
+ }.start()
}
}
}
}
- private fun onZipDownloadFinish(index: Int) {
+ private suspend fun onZipDownloadFinish(index: Int) = withContext(Dispatchers.Main) {
if(index >= 0 && index < tbtnlist.size) {
tbtnlist[index].setBackgroundResource(R.drawable.rndbg_checked)
tbtnlist[index].isChecked = false
+ tbtnlist[index].isEnabled = true
finishMap[index] = true
updateProgressBar()
that?.apply {
cdwn.postDelayed({
- if (mangaDlTools?.exit != false) return@postDelayed
+ if (mangaDlTools.exit) return@postDelayed
if (dldChapter == checkedChapter) {
checkedChapter = 0
setProgress2(0, 233)
@@ -299,8 +307,9 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference){
- addTbtn(data[0], data[1], data[2], data[3])
- urlArray += data[3]
+ private suspend fun addButtons(chapters: Array, caption: String) = withContext(Dispatchers.IO) {
+ chapters.forEach { chapter ->
+ val u = CMApi.getChapterInfoApiUrl(chapter.comic_path_word, chapter.uuid)?:""
+ addButton(chapter.name, chapter.uuid, caption, u)
+ urlArray += u
+ }
+ addDiv()
}
@SuppressLint("SetTextI18n")
- private fun addTbtn(title: String, uuid: String, caption: String, url: String) {
+ private suspend fun addButton(title: String, uuid: String, caption: String, url: String) = withContext(Dispatchers.Main) {
if ((tbtncnt % btnNumPerRow == 0) || isNewTitle) {
that?.ltbtn = that?.layoutInflater?.inflate(R.layout.line_horizonal_empty, that!!.ldwn, false)
that?.ldwn?.addView(that!!.ltbtn)
@@ -338,82 +351,86 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference::class.java)?.let {
for (group in it) {
that?.layoutInflater?.inflate(R.layout.line_caption, that!!.ldwn, false)?.let { tc ->
tc.tcptn.text = group.name
- that!!.ldwn.addView(
- tc,
- ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ withContext(Dispatchers.Main) {
+ that!!.ldwn.addView(
+ tc,
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
)
- )
- that!!.ldwn.addView(
- that!!.layoutInflater.inflate(R.layout.div_h, that!!.ldwn, false),
- ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
+ that!!.ldwn.addView(
+ that!!.layoutInflater.inflate(R.layout.div_h, that!!.ldwn, false),
+ ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
)
- )
+ }
isNewTitle = true
for (chapter in group.chapters) {
val newUrl = CMApi.getChapterInfoApiUrl(
@@ -421,10 +438,11 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference
+ if (l.code != 200 && l.code != 449) {
+ Toast.makeText(context, l.message, Toast.LENGTH_SHORT).show()
+ logout()
+ }
}
- MainActivity.member?.logout()
- }
- }.start()
+ } }
homeHandler = HomeHandler(WeakReference(this))
val theme = resources.newTheme()
@@ -92,12 +96,14 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
override fun onQueryTextChange(newText: CharSequence): Boolean {
if (newText.contentEquals("__notice_focus_change__") || newText.contentEquals(lastSearch)) return true
postDelayed({
- val diff = System.currentTimeMillis() - lastChangeTime
- if(diff > 500) {
- if (newText.isNotEmpty()) {
- Log.d("MyHF", "new text: $newText")
- lastSearch = newText.toString()
- adapter.refresh(newText)
+ lifecycleScope.launch {
+ val diff = System.currentTimeMillis() - lastChangeTime
+ if(diff > 500) {
+ if (newText.isNotEmpty()) {
+ Log.d("MyHF", "new text: $newText")
+ lastSearch = newText.toString()
+ adapter.refresh(newText)
+ }
}
}
}, 1024)
@@ -154,14 +160,16 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
}
}
- Thread{
- homeHandler.obtainMessage(-1, true).sendToTarget()
- while(!MainActivity.isDrawerClosed) sleep(233)
- //homeHandler.sendEmptyMessage(6) //removeAllViews
- homeHandler.fhib = null
- sleep(600)
- homeHandler.startLoad()
- }.start()
+ lifecycleScope.launch{
+ withContext(Dispatchers.IO) {
+ homeHandler.obtainMessage(-1, true).sendToTarget()
+ while(!MainActivity.isDrawerClosed) sleep(233)
+ //homeHandler.sendEmptyMessage(6) //removeAllViews
+ homeHandler.fhib = null
+ sleep(600)
+ homeHandler.startLoad()
+ }
+ }
}
}
@@ -261,14 +269,16 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
override fun getItemCount() = (results?.results?.list?.size?:0) + if (query?.isNotEmpty() == true) 1 else 0
- fun refresh(q: CharSequence) {
+ suspend fun refresh(q: CharSequence) = withContext(Dispatchers.IO) {
query = q.toString()
activity?.apply {
- AutoDownloadThread(getString(R.string.searchApiUrl).format(CMApi.myHostApiUrl, 0, query, type)) {
- results = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)
+ PausableDownloader(getString(R.string.searchApiUrl).format(CMApi.myHostApiUrl, 0, query, type)) {
+ results = Gson().fromJson(it.decodeToString(), BookListStructure::class.java)
count = results?.results?.total?:0
- runOnUiThread { notifyDataSetChanged() }
- }.start()
+ withContext(Dispatchers.Main) {
+ notifyDataSetChanged()
+ }
+ }.run()
}
}
}
diff --git a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt
index c5d67c4..5209065 100644
--- a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt
+++ b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt
@@ -3,7 +3,6 @@ package top.fumiama.copymanga.ui.home
import android.animation.ObjectAnimator
import android.graphics.Color
import android.os.Bundle
-import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
@@ -13,6 +12,7 @@ import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.animation.doOnEnd
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.bumptech.glide.Glide
@@ -23,6 +23,9 @@ import com.to.aboomy.pager2banner.ScaleInTransformer
import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.line_1bookline.view.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.json.ComicStructure
import top.fumiama.copymanga.json.IndexStructure
import top.fumiama.copymanga.template.http.AutoDownloadHandler
@@ -37,7 +40,7 @@ import java.lang.ref.WeakReference
class HomeHandler(private val that: WeakReference) : AutoDownloadHandler(
that.get()?.getString(R.string.mainPageApiUrl)!!.format(CMApi.myHostApiUrl),
IndexStructure::class.java,
- Looper.myLooper()!!,
+ that.get(),
9
) {
private val homeF get() = that.get()
@@ -47,7 +50,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
Log.d("MyHH", "Get fhib.")
if (field == null) {
field = homeF?.layoutInflater?.inflate(R.layout.viewpage_banner, homeF?.fhl, false)
- Thread{ homeF?.homeHandler?.sendEmptyMessage(3) }.start()
+ homeF?.homeHandler?.sendEmptyMessage(3)
}
return field
}
@@ -104,23 +107,17 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
if(exit) return
Toast.makeText(homeF?.context, R.string.web_error, Toast.LENGTH_SHORT).show()
}
- override fun doWhenFinishDownload() {
+ override suspend fun doWhenFinishDownload() = withContext(Dispatchers.IO) {
super.doWhenFinishDownload()
- if(exit) return
- try {
- Thread {
- sendEmptyMessage(2) //setSwipe
- sendEmptyMessage(7) //inflateBanner
- sendEmptyMessage(1) //inflateCardLines
- }.start()
- } catch (e: Exception) {
- Toast.makeText(homeF?.context, R.string.load_home_error, Toast.LENGTH_SHORT).show()
- }
+ if(exit) return@withContext
+ sendEmptyMessage(2) //setSwipe
+ sendEmptyMessage(7) //inflateBanner
+ sendEmptyMessage(1) //inflateCardLines
}
private fun inflateBanner() = homeF?.fhl?.addView(fhib)
- private fun inflateTopics(){
+ private suspend fun inflateTopics() {
index?.results?.topics?.list?.let {
var comics = arrayOf()
for((i, topic) in it.withIndex()){
@@ -135,7 +132,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateRec(){
+ private suspend fun inflateRec() {
index?.results?.recComics?.list?.let {
var comics = arrayOf()
for((i, rec) in it.withIndex()){
@@ -150,7 +147,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateRank(){
+ private suspend fun inflateRank(){
var comics = arrayOf()
index?.results?.rankDayComics?.list?.let {
for((i, book) in it.withIndex()){
@@ -175,7 +172,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateHot(){
+ private suspend fun inflateHot(){
index?.results?.hotComics?.let {
var comics = arrayOf()
for((i, rec) in it.withIndex()){
@@ -186,7 +183,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateNew(){
+ private suspend fun inflateNew(){
index?.results?.newComics?.let {
var comics = arrayOf()
for((i, rec) in it.withIndex()){
@@ -201,7 +198,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateFinish(){
+ private suspend fun inflateFinish(){
index?.results?.finishComics?.list?.let {
var comics = arrayOf()
for((i, rec) in it.withIndex()){
@@ -216,20 +213,24 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun inflateCardLines() = Thread {
- if (indexLines.isNotEmpty()) indexLines = arrayOf()
- inflateRec()
- inflateTopics()
- inflateHot()
- inflateNew()
- inflateFinish()
- inflateRank()
- for(i in indexLines.indices) {
- obtainMessage(8, i, 0).sendToTarget()
- sleep(512)
+ private fun inflateCardLines() {
+ homeF?.lifecycleScope?.launch {
+ withContext(Dispatchers.IO) {
+ if (indexLines.isNotEmpty()) indexLines = arrayOf()
+ inflateRec()
+ inflateTopics()
+ inflateHot()
+ inflateNew()
+ inflateFinish()
+ inflateRank()
+ for(i in indexLines.indices) {
+ obtainMessage(8, i, 0).sendToTarget()
+ sleep(512)
+ }
+ obtainMessage(-1, false).sendToTarget() //closeLoad
+ }
}
- obtainMessage(-1, false).sendToTarget() //closeLoad
- }.start()
+ }
private fun setBanner(v: Banner): Banner {
v.viewTreeObserver.addOnGlobalLayoutListener(object :
@@ -241,7 +242,7 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
v.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
- Thread{this.obtainMessage(5, v).sendToTarget()}.start() //setBannerInfo
+ obtainMessage(5, v).sendToTarget() //setBannerInfo
return v
}
@@ -264,20 +265,23 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
homeF?.fhov?.swipeRefreshLayout = sw
sw.setOnRefreshListener {
Log.d("MyHFH", "Refresh items.")
- //index = null
- //Thread{this@HomeHandler.obtainMessage(-1, true).sendToTarget()}.start() //startLoad
- Thread{
- index = null
- //fhib = null
- indexLines = arrayOf()
- this@HomeHandler.sendEmptyMessage(6) //removeAllViews
- sleep(300)
- this@HomeHandler.sendEmptyMessage(0) //setLayouts
- }.start()
+ homeF?.lifecycleScope?.launch {
+ withContext(Dispatchers.IO) {
+ index = null
+ //fhib = null
+ indexLines = arrayOf()
+ this@HomeHandler.sendEmptyMessage(6) //removeAllViews
+ sleep(300)
+ this@HomeHandler.sendEmptyMessage(0) //setLayouts
+ }
+ }
}
}
- private fun allocateLine(title: String, iconResId: Int, comics: Array, finish: Boolean = false, isTopic: Boolean = false, onClick: (() -> Unit)? = null): Int{
+ private suspend fun allocateLine(
+ title: String, iconResId: Int, comics: Array,
+ finish: Boolean = false, isTopic: Boolean = false, onClick: (() -> Unit)? = null
+ ): Int = withContext(Dispatchers.IO) {
val p = indexLines.size
val c = comics.size / 3
homeF?.layoutInflater?.inflate(
@@ -285,22 +289,24 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
1 -> R.layout.line_1bookline
2 -> R.layout.line_2bookline
3 -> R.layout.line_3bookline
- else -> return -1
- }, homeF!!.fhl, false)?.apply {
- scanCards(this, comics, finish, isTopic)
- rttitle.text = title
- ir.setImageResource(iconResId)
- setLineHeight(this, c)
- if(onClick != null) setOnClickListener { onClick() }
+ else -> return@withContext -1
+ }, homeF!!.fhl, false)?.apply {
+ withContext(Dispatchers.Main) {
+ scanCards(this@apply, comics, finish, isTopic)
+ rttitle.text = title
+ ir.setImageResource(iconResId)
+ setLineHeight(this@apply, c)
+ if(onClick != null) setOnClickListener { onClick() }
+ }
indexLines += this
}
- return p
+ return@withContext p
}
- private fun scanCards(v: View, comics: Array, finish: Boolean, isTopic: Boolean){
+ private suspend fun scanCards(v: View, comics: Array, finish: Boolean, isTopic: Boolean) = withContext(Dispatchers.IO) {
var id = v.rc1.id
var card = v.findViewById(id)
- for (data in comics){
+ for (data in comics) {
setCards(
card.cic,
data.path_word,
@@ -313,10 +319,10 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
}
- private fun setCards(cv: CardView, pw: String, name: String, img: String, isFinal: Boolean, isTopic: Boolean) {
+ private suspend fun setCards(cv: CardView, pw: String, name: String, img: String, isFinal: Boolean, isTopic: Boolean) = withContext(Dispatchers.Main) {
cv.tic.text = name
homeF?.let {
- if(img.startsWith("http")) it.activity?.runOnUiThread {
+ if(img.startsWith("http")) {
Glide.with(it).load(GlideUrl(CMApi.proxy?.wrap(img)?:img, CMApi.myGlideHeaders))
.addListener(GlideHideLottieViewListener(WeakReference(cv.laic)))
.timeout(20000).into(cv.imic)
@@ -348,4 +354,4 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH
}
})
}
-}
\ No newline at end of file
+}
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 1b97597..40b07fc 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
@@ -3,19 +3,22 @@ package top.fumiama.copymanga.ui.vm
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.Dialog
-import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
-import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
+import androidx.lifecycle.lifecycleScope
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_viewmanga.*
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.withContext
import top.fumiama.copymanga.json.Chapter2Return
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
@@ -27,13 +30,12 @@ import java.lang.ref.WeakReference
import java.text.SimpleDateFormat
import java.util.*
-class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
- url, Chapter2Return::class.java, Looper.myLooper()!!
+class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, private val weeks: Array) : AutoDownloadHandler(
+ chapterUrl, Chapter2Return::class.java, activity
) {
var manga: Chapter2Return? = null
private val wv = WeakReference(activity)
private val drawer = wv.get()?.infcard
- private val weeks = wv.get()?.getStringArray(R.array.weeks)
private var hasDrawerShown = false
val dl = activity.let {
val re = Dialog(it)
@@ -50,7 +52,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
val cal = Calendar.getInstance()
val w = cal[Calendar.DAY_OF_WEEK]
if (w > 7 || w <= 0) return ""
- return weeks?.get(w-1) ?: ""
+ return weeks[w-1]
}
private var remainingImageCount = 0
@@ -72,7 +74,11 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
LOAD_IMG_ON -> {
val scaleImageView = msg.obj as ScaleImageView
// msg.arg2: isLast
- wv.get()?.loadImgOn(scaleImageView, msg.arg1)
+ wv.get()?.apply {
+ lifecycleScope.launch {
+ loadImgOn(scaleImageView, msg.arg1)
+ }
+ }
//scaleImageView.setHeight2FitImgWidth()
//if(msg.arg2 == 1) sendEmptyMessage(DELAYED_RESTORE_PAGE_NUMBER)
}
@@ -86,8 +92,8 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
LOAD_ITEM_SCROLL_MODE -> loadScrollMode(msg.arg1, msg.obj as? Runnable?)
LOAD_SCROLL_MODE -> loadScrollMode()
- LOAD_ITEM_IMAGES_INTO_LINE -> loadImagesIntoLine(msg.arg1, msg.obj as? Runnable?)
- LOAD_IMAGES_INTO_LINE -> loadImagesIntoLine()
+ LOAD_ITEM_IMAGES_INTO_LINE -> wv.get()?.lifecycleScope?.launch { loadImagesIntoLine(msg.arg1, msg.obj as? Runnable?) }
+ LOAD_IMAGES_INTO_LINE -> wv.get()?.lifecycleScope?.launch { loadImagesIntoLine() }
RESTORE_PAGE_NUMBER -> {
sendEmptyMessage(DIALOG_HIDE)
wv.get()?.restorePN()
@@ -141,17 +147,22 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
override fun onError() {
super.onError()
if(exit) return
- wv.get()?.toolsBox?.toastError(R.string.download_chapter_info_failed)
+ wv.get()?.apply {
+ lifecycleScope.launch {
+ toolsBox.toastError(R.string.download_chapter_info_failed)
+ }
+ }
}
- override fun doWhenFinishDownload() {
+ override suspend fun doWhenFinishDownload() {
super.doWhenFinishDownload()
if(exit) return
prepareManga()
}
- fun loadFromFile(file: File): Boolean {
- return try {
+ suspend fun loadFromFile(file: File): Boolean = withContext(Dispatchers.IO) {
+ fakeLoad()
+ return@withContext try {
val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json")
if(jsonFile.exists()) {
manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java)
@@ -180,7 +191,11 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
}
}
- private fun prepareManga(){
+ private suspend fun fakeLoad() {
+ PausableDownloader(chapterUrl) { _ -> }.run()
+ }
+
+ private suspend fun prepareManga() = withContext(Dispatchers.Main) {
if(comicName == null) {
comicName = manga?.results?.comic?.name
}
@@ -188,7 +203,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
wv.get()?.initManga()
wv.get()?.vprog?.visibility = View.GONE
}
- private fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = Thread{
+ private suspend fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = withContext(Dispatchers.IO) {
val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)
Log.d("MyVMH", "Fun: loadImagesIntoLine($item, $maxCount)")
wv.get()?.realCount?.let { count ->
@@ -204,11 +219,11 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget()
obtainMessage(DO_LAMBDA, Runnable{
doAfter?.run()
- wv.get()?.let { it.updateSeekBar(0) }
+ wv.get()?.updateSeekBar(0)
}).sendToTarget()
}
}
- }.start()
+ }
private fun loadScrollMode() {
sendEmptyMessage(DIALOG_SHOW)
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 0210737..0414ebe 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
@@ -21,6 +21,7 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat
import androidx.core.content.edit
+import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
@@ -38,9 +39,12 @@ import kotlinx.android.synthetic.main.widget_infodrawer.*
import kotlinx.android.synthetic.main.widget_titlebar.*
import kotlinx.android.synthetic.main.widget_titlebar.view.*
import kotlinx.android.synthetic.main.widget_viewmangainfo.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.template.general.TitleActivityTemplate
-import top.fumiama.copymanga.template.http.AutoDownloadThread
+import top.fumiama.copymanga.template.http.PausableDownloader
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.thread.TimeThread
@@ -128,50 +132,59 @@ class ViewMangaActivity : TitleActivityTemplate() {
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
- val settingsPref = MainActivity.mainWeakReference?.get()?.let { PreferenceManager.getDefaultSharedPreferences(it) }
- settingsPref?.getBoolean("settings_cat_vm_sw_always_dark_bg", false)?.let {
- if (it) {
- Log.d("MyVM", "force dark")
- delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES
- } else {
- delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
- }
- }
postponeEnterTransition()
setContentView(R.layout.activity_viewmanga)
super.onCreate(null)
+ lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ val settingsPref = MainActivity.mainWeakReference?.get()?.let { PreferenceManager.getDefaultSharedPreferences(it) }
+ settingsPref?.getBoolean("settings_cat_vm_sw_always_dark_bg", false)?.let {
+ if (it) {
+ Log.d("MyVM", "force dark")
+ delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES
+ } else {
+ delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
+ }
+ }
+ va = WeakReference(this@ViewMangaActivity)
+ //dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
+ //zipFirst = intent.getStringExtra("callFrom") == "zipFirst"
+ intent.getStringArrayExtra("urlArray")?.let { urlArray = it }
+ cut = pb["useCut"]
+ r2l = pb["r2l"]
+ verticalLoadMaxCount = settingsPref?.getInt("settings_cat_vm_sb_vertical_max", 20)?.let { if(it > 0) it else 20 }?:20
+ isVertical = pb["vertical"]
+ notUseVP = pb["noVP"] || isVertical
+ //url = intent.getStringExtra("url")
+ withContext(Dispatchers.Main) {
+ handler = VMHandler(this@ViewMangaActivity, if(urlArray.isNotEmpty()) urlArray[position] else "", resources.getStringArray(R.array.weeks))
+ withContext(Dispatchers.IO) {
+ settingsPref?.getInt("settings_cat_vm_sb_quality", 100)?.let { q = if (it > 0) it else 100 }
+ tt = TimeThread(handler, VMHandler.SET_NET_INFO, 10000)
+ tt.canDo = true
+ tt.start()
+ volTurnPage = settingsPref?.getBoolean("settings_cat_vm_sw_vol_turn", false)?:false
+ am = getSystemService(Service.AUDIO_SERVICE) as AudioManager
+ if (!noCellarAlert) noCellarAlert = settingsPref?.getBoolean("settings_cat_net_sw_use_cellar", false) == true
+ fullyHideInfo = settingsPref?.getBoolean("settings_cat_vm_sw_hide_info", false) == true
- va = WeakReference(this)
- //dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
- //zipFirst = intent.getStringExtra("callFrom") == "zipFirst"
- intent.getStringArrayExtra("urlArray")?.let { urlArray = it }
- cut = pb["useCut"]
- r2l = pb["r2l"]
- verticalLoadMaxCount = settingsPref?.getInt("settings_cat_vm_sb_vertical_max", 20)?.let { if(it > 0) it else 20 }?:20
- isVertical = pb["vertical"]
- notUseVP = pb["noVP"] || isVertical
- //url = intent.getStringExtra("url")
- handler = VMHandler(this, if(urlArray.isNotEmpty()) urlArray[position] else "")
- settingsPref?.getInt("settings_cat_vm_sb_quality", 100)?.let { q = if (it > 0) it else 100 }
- tt = TimeThread(handler, VMHandler.SET_NET_INFO)
- tt.canDo = true
- tt.start()
- volTurnPage = settingsPref?.getBoolean("settings_cat_vm_sw_vol_turn", false)?:false
- am = getSystemService(Service.AUDIO_SERVICE) as AudioManager
- if (!noCellarAlert) noCellarAlert = settingsPref?.getBoolean("settings_cat_net_sw_use_cellar", false) == true
- fullyHideInfo = settingsPref?.getBoolean("settings_cat_vm_sw_hide_info", false) == true
-
- Log.d("MyVM", "Now ZipFile is $zipFile")
- try {
- if (zipFile != null && zipFile?.exists() == true) {
- if (!handler.loadFromFile(zipFile!!)) prepareImgFromWeb()
- } else prepareImgFromWeb()
- } catch (e: Exception) {
- e.printStackTrace()
- toolsBox.toastError(R.string.load_manga_error)
+ Log.d("MyVM", "Now ZipFile is $zipFile")
+ try {
+ if (zipFile != null && zipFile?.exists() == true) {
+ if (!handler.loadFromFile(zipFile!!)) prepareImgFromWeb()
+ } else prepareImgFromWeb()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ toolsBox.toastError(R.string.load_manga_error)
+ }
+ withContext(Dispatchers.Main) {
+ startPostponedEnterTransition()
+ ObjectAnimator.ofFloat(vcp, "alpha", 0.1f, 1f).setDuration(1000).start()
+ }
+ }
+ }
+ }
}
- startPostponedEnterTransition()
- ObjectAnimator.ofFloat(vcp, "alpha", 0.1f, 1f).setDuration(1000).start()
}
@Suppress("DEPRECATION")
@@ -293,12 +306,12 @@ class ViewMangaActivity : TitleActivityTemplate() {
return op.outWidth.toFloat() / op.outHeight.toFloat() > 1
}
- fun countZipEntries(doWhenFinish : (count: Int) -> Unit) = Thread{
+ suspend fun countZipEntries(doWhenFinish : suspend (count: Int) -> Unit) = withContext(Dispatchers.IO) {
if (zipFile != null) try {
Log.d("MyVM", "zip: $zipFile")
val zip = ZipFile(zipFile)
count = zip.size()
- if(cut) zip.entries().toList().sortedBy{it.name.substringBefore('.').toInt()}.forEachIndexed { i, it ->
+ if(cut) zip.entries().toList().sortedBy{ it.name.substringBefore('.').toInt()}.forEachIndexed { i, it ->
val useCut = canCut(zip.getInputStream(it))
isCut += useCut
indexMap += i + 1
@@ -306,13 +319,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
Log.d("MyVM", "[$i] 分析: ${it.name}, cut: $useCut")
}
} catch (e: Exception) {
- runOnUiThread { toolsBox.toastError(R.string.count_zip_entries_error) }
+ withContext(Dispatchers.Main) { toolsBox.toastError(R.string.count_zip_entries_error) }
}
- runOnUiThread {
- Log.d("MyVM", "开始加载控件")
- doWhenFinish(count)
- }
- }.start()
+ Log.d("MyVM", "开始加载控件")
+ doWhenFinish(count)
+ }
private fun getPageNumber(): Int {
return if (r2l && !notUseVP) realCount - vp.currentItem
@@ -336,7 +347,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
loadOneImg()
} catch (e: Exception) {
e.printStackTrace()
- toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem))
+ lifecycleScope.launch {
+ toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem))
+ }
}
}
} else {
@@ -382,9 +395,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
private fun cutBitmap(bitmap: Bitmap, isEnd: Boolean) = Bitmap.createBitmap(bitmap, if(!isEnd) 0 else (bitmap.width/2), 0, bitmap.width/2, bitmap.height)
- private fun loadImg(imgView: ScaleImageView, bitmap: Bitmap, useCut: Boolean, isLeft: Boolean, isPlaceholder: Boolean = true) {
+ private suspend fun loadImg(imgView: ScaleImageView, bitmap: Bitmap, useCut: Boolean, isLeft: Boolean, isPlaceholder: Boolean = true) = withContext(Dispatchers.IO) {
val bitmap2load = if(!isPlaceholder && useCut) cutBitmap(bitmap, isLeft) else bitmap
- runOnUiThread {
+ withContext(Dispatchers.Main) {
imgView.setImageBitmap(bitmap2load)
if(!isPlaceholder && isVertical) {
imgView.setHeight2FitImgWidth()
@@ -393,11 +406,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
}
- private fun loadImgUrlInto(imgView: ScaleImageView, url: String, useCut: Boolean, isLeft: Boolean){
+ private suspend fun loadImgUrlInto(imgView: ScaleImageView, url: String, useCut: Boolean, isLeft: Boolean){
Log.d("MyVM", "Load from adt: $url")
- AutoDownloadThread(CMApi.resolution.wrap(CMApi.proxy?.wrap(url)?:url), 1000) {
- it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) }
- }.start()
+ PausableDownloader(CMApi.resolution.wrap(CMApi.proxy?.wrap(url)?:url), 1000) {
+ it.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) }
+ }.run()
}
private fun getLoadingBitmap(position: Int): Bitmap {
@@ -414,9 +427,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
return loading
}
- fun loadImgOn(imgView: ScaleImageView, position: Int) {
+ suspend fun loadImgOn(imgView: ScaleImageView, position: Int) = withContext(Dispatchers.IO) {
Log.d("MyVM", "Load img: $position")
- if (position < 0 || position > realCount) return
+ if (position < 0 || position > realCount) return@withContext
val index2load = if(cut) abs(indexMap[position]) -1 else position
val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[position] > 0
@@ -427,58 +440,58 @@ class ViewMangaActivity : TitleActivityTemplate() {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
val sleepTime = loadImgOnWait.getAndIncrement().toLong()*200
Log.d("MyVM", "loadImgOn sleep: $sleepTime ms")
- Thread {
- val re = tasks?.get(index2load)
- if (sleepTime > 0 && re?.isDone != true) Thread.sleep(sleepTime)
- if (re != null) {
- if(!re.isDone) re.run()
- val data = re.get()
- if(data != null && data.isNotEmpty()) {
- BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
- loadImg(imgView, it, useCut, isLeft, false)
- runOnUiThread { Log.d("MyVM", "Load position $position from task") }
- }?:runOnUiThread { Log.d("MyVM", "null bitmap at $position") }
- }
- else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
+ val re = tasks?.get(index2load)
+ if (sleepTime > 0 && re?.isDone != true) Thread.sleep(sleepTime)
+ if (re != null) {
+ if(!re.isDone) re.run()
+ val data = re.get()
+ if(data != null && data.isNotEmpty()) {
+ BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
+ loadImg(imgView, it, useCut, isLeft, false)
+ Log.d("MyVM", "Load position $position from task")
+ }?:Log.d("MyVM", "null bitmap at $position")
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
- loadImgOnWait.decrementAndGet()
- tasks?.apply {
- if (index2load >= size) return@apply
- val p = if (index2load == size-1) index2load-1 else index2load+1
- var delta = 1
- var isMinus = false
- var pos = p
- var maxCount = size
- while (pos in indices && get(pos)?.isDone != false && tasksRunStatus?.get(pos) != false && maxCount-- > 0) {
- runOnUiThread { Log.d("MyVM", "search $pos") }
- pos = p + if (isMinus) -delta else delta
- if (pos !in indices) {
- isMinus = !isMinus
- if (!isMinus) delta++
- pos = p + if (isMinus) -delta else delta
- if (pos !in indices) return@apply
- }
+ }
+ else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
+ loadImgOnWait.decrementAndGet()
+ tasks?.apply {
+ if (index2load >= size) return@apply
+ val p = if (index2load == size-1) index2load-1 else index2load+1
+ var delta = 1
+ var isMinus = false
+ var pos = p
+ var maxCount = size
+ while (pos in indices && get(pos)?.isDone != false && tasksRunStatus?.get(pos) != false && maxCount-- > 0) {
+ Log.d("MyVM", "search $pos")
+ pos = p + if (isMinus) -delta else delta
+ if (pos !in indices) {
isMinus = !isMinus
if (!isMinus) delta++
+ pos = p + if (isMinus) -delta else delta
+ if (pos !in indices) return@apply
}
- if (pos !in indices || tasksRunStatus?.get(pos) != false) return@apply
- runOnUiThread { Log.d("MyVM", "Preload position $pos from task") }
- get(pos)?.apply {
- if(!isDone) {
- tasksRunStatus?.set(pos, true)
- run()
- }
+ isMinus = !isMinus
+ if (!isMinus) delta++
+ }
+ if (pos !in indices || tasksRunStatus?.get(pos) != false) return@apply
+ Log.d("MyVM", "Preload position $pos from task")
+ get(pos)?.apply {
+ if(!isDone) {
+ tasksRunStatus?.set(pos, true)
+ run()
}
}
- }.start()
+ }
}
imgView.visibility = View.VISIBLE
}
private fun loadOneImg() {
- loadImgOn(onei, currentItem)
- updateSeekBar()
+ lifecycleScope.launch {
+ loadImgOn(onei, currentItem)
+ updateSeekBar()
+ }
}
private fun initImgList(){
@@ -494,7 +507,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
// handler.dl?.hide()
}
- private fun getImgBitmap(position: Int): Bitmap? =
+ private suspend fun getImgBitmap(position: Int): Bitmap? = withContext(Dispatchers.IO) {
if (position >= count || position < 0) null
else {
val zip = ZipFile(zipFile)
@@ -511,7 +524,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
} catch (e: Exception) {
if (i == 1) {
e.printStackTrace()
- Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show()
+ withContext(Dispatchers.Main) {
+ Toast.makeText(this@ViewMangaActivity, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show()
+ }
}
null
}
@@ -522,6 +537,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
bitmap
}
+ }
private fun setIdPosition(position: Int) {
infoDrawerDelta = position.toFloat()
@@ -548,8 +564,10 @@ class ViewMangaActivity : TitleActivityTemplate() {
}*/
} catch (e: Exception) {
e.printStackTrace()
- toolsBox.toastError(R.string.load_chapter_error)
- finish()
+ lifecycleScope.launch {
+ toolsBox.toastError(R.string.load_chapter_error)
+ finish()
+ }
}
}
@@ -812,9 +830,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
val index2load = if(cut) abs(indexMap[pos]) -1 else pos
val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[pos] > 0
- if (zipFile?.exists() == true) getImgBitmap(index2load)?.let {
- //Glide.with(this@ViewMangaActivity).load(if(useCut) cutBitmap(it, isLeft) else it).into(holder.itemView.onei)
- holder.itemView.onei.setImageBitmap(if(useCut) cutBitmap(it, isLeft) else it)
+ if (zipFile?.exists() == true) lifecycleScope.launch {
+ getImgBitmap(index2load)?.let {
+ //Glide.with(this@ViewMangaActivity).load(if(useCut) cutBitmap(it, isLeft) else it).into(holder.itemView.onei)
+ holder.itemView.onei.setImageBitmap(if(useCut) cutBitmap(it, isLeft) else it)
+ }
}
else getImgUrl(index2load)?.let{
if(useCut){
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 28abaef..244d4eb 100644
--- a/app/src/main/java/top/fumiama/copymanga/user/Member.kt
+++ b/app/src/main/java/top/fumiama/copymanga/user/Member.kt
@@ -1,20 +1,26 @@
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
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R
+import java.net.URLEncoder
+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 {
- CMApi.getLoginConnection(username, pwd, salt)?.apply {
- Gson().fromJson(inputStream.reader(), LoginInfoStructure::class.java)?.let { data ->
+ getLoginConnection(username, pwd, salt).apply {
+ Gson().fromJson(
+ JsonReader(inputStream.reader()), LoginInfoStructure::class.java
+ )?.let { data ->
disconnect()
if(data.code == 200) {
pref.edit()?.apply {
@@ -23,7 +29,7 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
putString("username", data.results?.username)
putString("nickname", data.results?.nickname)
apply()
- return@withContext refreshAvatar()
+ return@withContext info()
}
}
return@withContext data
@@ -42,37 +48,37 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
}
-
- fun refreshAvatar() : LoginInfoStructure {
+ /**
+ * 获得登录信息并更新头像
+ * @return 登录态
+ * - **code**: 449: 未登录, 450: 有 Exception
+ * - **message**: 可以 toast 的信息
+ */
+ suspend fun info() : LoginInfoStructure = withContext(Dispatchers.IO) {
if (!pref.contains("token")) {
val l = LoginInfoStructure()
- l.code = 400
+ l.code = 449
l.message = getString(R.string.noLogin)
- return l
+ return@withContext l
}
- try {
- DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format(
- CMApi.myHostApiUrl))?.decodeToString()?.let {
- val l = Gson().fromJson(it, LoginInfoStructure::class.java)
- if(l.code == 200) pref.edit()?.apply {
- putString("avatar", l.results.avatar)
- apply()
- }
- return l
+ return@withContext try {
+ val l = Gson().fromJson(DownloadTools.getHttpContent(
+ getString(R.string.memberInfoApiUrl).format(CMApi.myHostApiUrl)).decodeToString(),
+ 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 = 400
+ l.code = 450
l.message = "${getString(R.string.login_get_avatar_failed)}: ${e.localizedMessage}"
- return l
+ l
}
- val l = LoginInfoStructure()
- l.code = 400
- l.message = getString(R.string.login_get_avatar_failed)
- return l
}
- fun logout() {
+ suspend fun logout() = withContext(Dispatchers.IO) {
pref.edit()?.apply {
remove("token")
remove("user_id")
@@ -82,4 +88,19 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
apply()
}
}
+
+ private fun getLoginConnection(username: String, pwd: String, salt: Int) =
+ getString(R.string.loginApiUrl).format(CMApi.myHostApiUrl).let {
+ DownloadTools.getApiConnection(it, "POST").apply {
+ pref.apply {
+ doOutput = true
+ setRequestProperty("content-type", "application/x-www-form-urlencoded;charset=utf-8")
+ setRequestProperty("platform", "3")
+ setRequestProperty("accept", "application/json")
+ val r = if(!getBoolean("settings_cat_net_sw_use_foreign", false)) "1" else "0"
+ val pwdEncoded = Base64.encode("$pwd-$salt".toByteArray(), Base64.DEFAULT).decodeToString()
+ outputStream.write("username=${URLEncoder.encode(username, Charset.defaultCharset().name())}&password=$pwdEncoded&salt=$salt&platform=3&authorization=Token+&version=1.4.4&source=copyApp®ion=$r&webp=1".toByteArray())
+ }
+ }
+ }
}
diff --git a/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt b/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt
index ff2eb5e..0bc40a9 100644
--- a/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt
+++ b/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt
@@ -14,6 +14,8 @@ import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.widget.ImageView
+import androidx.lifecycle.lifecycleScope
+import kotlinx.coroutines.launch
import top.fumiama.copymanga.ui.vm.PagesManager
import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import top.fumiama.dmzj.copymanga.R
@@ -564,7 +566,11 @@ class ScaleImageView : ImageView {
}
}catch (e:Exception){
e.printStackTrace()
- ViewMangaActivity.va?.get()?.toolsBox?.toastError(R.string.show_image_error_try_lower_resolution, false)
+ ViewMangaActivity.va?.get()?.apply {
+ lifecycleScope.launch {
+ toolsBox.toastError(R.string.show_image_error_try_lower_resolution, false)
+ }
+ }
}
}
////////////////////////////////有效性判断////////////////////////////////
diff --git a/app/src/main/res/layout/line_bookinfo.xml b/app/src/main/res/layout/line_bookinfo.xml
index b6bae54..c02c370 100644
--- a/app/src/main/res/layout/line_bookinfo.xml
+++ b/app/src/main/res/layout/line_bookinfo.xml
@@ -19,7 +19,7 @@
]>
-
+
拷贝漫画
设定
@@ -81,7 +81,7 @@
https://%1$s/api/v3/member/collect/comic
https://copymanga.azurewebsites.net/api/img?code=%1$s&url=%2$s
- https://hi77-overseas.mangafuna.xyz/
+ ^https://[0-9a-z-]+\.mangafuna\.xyz/
settings_cat_net_et_img_proxy_code