mirror of
https://github.com/fumiama/copymanga.git
synced 2026-06-05 07:20:23 +08:00
v2.2.0
修复 1. 详情页按钮在某些机型显示不全 2. 图床代理不正确打开导致的闪退 3. 下载中取消选择则闪退 4. 断点继续下载的zip错误 5. 浏览历史标记显示错误 6. 浏览已下载章节时不能记录到云端 7. 进其他书返回后漫画下载变为最上层 优化 1. 进一步协程化CardList, HTTP/文件读写等 2. 各模块加载速度
This commit is contained in:
2
.idea/dictionaries/fumiama.xml
generated
2
.idea/dictionaries/fumiama.xml
generated
@@ -3,7 +3,9 @@
|
||||
<words>
|
||||
<w>imgs</w>
|
||||
<w>lowpan</w>
|
||||
<w>mangafuna</w>
|
||||
<w>nisi</w>
|
||||
<w>pausable</w>
|
||||
<w>reilia</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<MainActivity>? = null
|
||||
var isDrawerClosed = true
|
||||
var ime: InputMethodManager? = null
|
||||
|
||||
10
app/src/main/java/top/fumiama/copymanga/manga/Book.kt
Normal file
10
app/src/main/java/top/fumiama/copymanga/manga/Book.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package top.fumiama.copymanga.manga
|
||||
|
||||
class Book(val pathWord: String, val readLocally: Boolean = false) {
|
||||
/**
|
||||
* 更新云端最新信息
|
||||
*/
|
||||
suspend fun update() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Fragment>) {
|
||||
super.initCardList(weakReference)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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<Quest>) {
|
||||
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<String>, refer: String?) {
|
||||
Thread{
|
||||
private fun packZipFile(fileName: String, imgUrls: Array<String>) {
|
||||
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
|
||||
|
||||
@@ -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<ByteArray?>? =
|
||||
/*fun touch(url: String?): FutureTask<ByteArray?>? =
|
||||
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<ByteArray?>? =
|
||||
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()
|
||||
|
||||
@@ -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)?:"<no prefix>"
|
||||
private val apiRegex = Regex(MainActivity.mainWeakReference?.get()?.getString(apiRegexID)?:"<no prefix>")
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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<Activity>? = 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()
|
||||
}
|
||||
|
||||
@@ -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<BookHandler?> = AtomicReference(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<BookFragment>, 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<BookFragment>, val path: String)
|
||||
}
|
||||
var book: BookInfoStructure? = null
|
||||
private var complete = false
|
||||
var ads = emptyArray<AutoDownloadThread>()
|
||||
var ads = emptyArray<PausableDownloader>()
|
||||
var gpws = arrayOf<String>()
|
||||
var keys = arrayOf<String>()
|
||||
var cnts = intArrayOf()
|
||||
var vols: Array<VolumeStructure>? = null
|
||||
var chapterNames = arrayOf<String>()
|
||||
var collect: Int = -1
|
||||
var json: String? = null
|
||||
private val divider get() = that?.layoutInflater?.inflate(R.layout.div_h, that?.lbl, false)
|
||||
|
||||
var urlArray = arrayOf<String>()
|
||||
@@ -87,7 +91,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, 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<BookFragment>, 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<BookFragment>, 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<BookFragment>, 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<BookFragment>, 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<BookFragment>, 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<BookFragment>, 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<BookFragment>, val path: String)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initComicData() = Thread {
|
||||
private suspend fun initComicData() = withContext(Dispatchers.IO) withIO@ {
|
||||
var volumes = emptyArray<VolumeStructure>()
|
||||
val counts = cnts.clone()
|
||||
gpws.forEachIndexed { i, gpw ->
|
||||
@@ -358,49 +361,58 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
|
||||
val times = counts[i] / 100
|
||||
val remain = counts[i] % 100
|
||||
val re = arrayOfNulls<VolumeStructure>(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<ChapterStructure>()
|
||||
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<ChapterStructure>()
|
||||
re.forEach { v ->
|
||||
v?.results?.list?.forEach {
|
||||
s += it
|
||||
}
|
||||
}
|
||||
r?.results?.list = s
|
||||
r?.apply { volumes += this }
|
||||
} else re[0]?.apply { volumes += this }
|
||||
}
|
||||
|
||||
var c = 0
|
||||
while (c < 80 && volumes.size != gpws.size) {
|
||||
sleep(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<BookFragment>, 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<BookFragment>, val path: String)
|
||||
}
|
||||
setViewManga()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun saveVolumes(volumes: Array<VolumeStructure>) {
|
||||
private suspend fun saveVolumes(volumes: Array<VolumeStructure>) = withContext(Dispatchers.IO) {
|
||||
that?.context?.getExternalFilesDir("")?.let { home ->
|
||||
book?.results?.comic?.name?.let { name ->
|
||||
val mangaFolder = File(home, name)
|
||||
@@ -429,27 +441,25 @@ class BookHandler(private val th: WeakReference<BookFragment>, 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<BookFragment>, 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
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMenu(items: Array<out ThemeStructure>, 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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AutoDownloadThread>()
|
||||
private var ads = emptyArray<PausableDownloader>()
|
||||
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<VolumeStructure>, isFromFile: Boolean = false, groupArray: Array<String>? =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<VolumeStructure>, isFromFile: Boolean = false, groupArray: Array<String>? =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<VolumeStructure>::class.java)
|
||||
private fun loadFromJson(json: String) = Gson().fromJson(json, Array<VolumeStructure>::class.java)
|
||||
private fun loadGroupsFromFile(file: File) = Gson().fromJson(file.reader(), Array<String>::class.java)
|
||||
|
||||
/*private fun setMenuInvisible(menu: Menu){
|
||||
menu.findItem(R.id.action_download)?.isVisible = false
|
||||
}*/
|
||||
|
||||
private fun initComicData(pw: String?, gpws: Array<String>?, counts: IntArray?) = Thread {
|
||||
private suspend fun initComicData(pw: String?, gpws: Array<String>?, counts: IntArray?) = withContext(Dispatchers.IO) {
|
||||
var volumes = emptyArray<VolumeStructure>()
|
||||
if (gpws != null) {
|
||||
gpws.forEachIndexed { i, gpw ->
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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<ComicDlFragme
|
||||
that?.tdwn?.text = "${dldChapter}/${checkedChapter}"
|
||||
}
|
||||
6 -> 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<String>)
|
||||
11 -> addCaption(msg.obj as String)
|
||||
12 -> addDiv()
|
||||
//10 -> addButton(msg.obj as Array<String>)
|
||||
//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<String>()
|
||||
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<ComicDlFragme
|
||||
)
|
||||
)
|
||||
}
|
||||
private fun addCaption(title: String){
|
||||
private suspend fun addCaption(title: String, body: suspend() -> 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<ComicDlFragme
|
||||
)
|
||||
addDiv()
|
||||
isNewTitle = true
|
||||
body()
|
||||
}
|
||||
private fun deleteChapter(f: File, v: ChapterToggleButton) {
|
||||
private suspend fun deleteChapter(f: File, v: ChapterToggleButton) = withContext(Dispatchers.IO) {
|
||||
f.delete()
|
||||
v.setBackgroundResource(R.drawable.toggle_button)
|
||||
v.isChecked = false
|
||||
withContext(Dispatchers.Main) {
|
||||
v.setBackgroundResource(R.drawable.toggle_button)
|
||||
v.isChecked = false
|
||||
}
|
||||
}
|
||||
private fun deleteChapters(zipf: File, index: Int) {
|
||||
private suspend fun deleteChapters(zipf: File, index: Int) = withContext(Dispatchers.IO) {
|
||||
if (multiSelect) {
|
||||
for (i in tbtnlist) {
|
||||
if (i.isChecked) {
|
||||
@@ -183,7 +185,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
|
||||
end
|
||||
).setDuration(duration).start()
|
||||
}
|
||||
private fun setComponents() {
|
||||
private suspend fun setComponents() = withContext(Dispatchers.Main) {
|
||||
val widthData = toolsBox.calcWidthFromDpRoot(8, 64)
|
||||
btnNumPerRow = widthData[0]
|
||||
btnw = widthData[1]
|
||||
@@ -210,23 +212,21 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
|
||||
that!!.pdwn.progress = 0
|
||||
if (downloading || checkedChapter == 0) {
|
||||
mangaDlTools.wait = !mangaDlTools.wait!!
|
||||
} else {
|
||||
} else that?.lifecycleScope?.launch {
|
||||
downloading = true
|
||||
Thread {
|
||||
sendEmptyMessage(9)
|
||||
finishMap = arrayOfNulls(tbtnlist.size)
|
||||
downloadChapterPages()
|
||||
}.start()
|
||||
sendEmptyMessage(9)
|
||||
finishMap = arrayOfNulls(tbtnlist.size)
|
||||
downloadChapterPages()
|
||||
}
|
||||
}
|
||||
}
|
||||
that?.cdwn?.setOnLongClickListener {
|
||||
Thread { sendEmptyMessage(4) }.start()
|
||||
sendEmptyMessage(4)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
mangaDlTools.onDownloadedListener = object :MangaDlTools.OnDownloadedListener{
|
||||
mangaDlTools.onDownloadedListener = object :MangaDlTools.OnDownloadedListener {
|
||||
override fun handleMessage(index: Int, isSuccess: Boolean, message: String) {
|
||||
that?.activity?.runOnUiThread {
|
||||
that?.lifecycleScope?.launch {
|
||||
if(isSuccess) onZipDownloadFinish(index)
|
||||
else onZipDownloadFailure(index, message)
|
||||
}
|
||||
@@ -240,7 +240,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
|
||||
isSuccess: Boolean,
|
||||
message: String
|
||||
) {
|
||||
that?.activity?.runOnUiThread {
|
||||
that?.lifecycleScope?.launch {
|
||||
if(isSuccess) {
|
||||
tbtnlist[index].text = if(downloaded == 0 && total == 0) tbtnlist[index].chapterName else "$downloaded/$total"
|
||||
} else {
|
||||
@@ -262,30 +262,38 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
|
||||
"确定", null, "取消", { multiSelect = true })
|
||||
}
|
||||
|
||||
private fun downloadChapterPages() {
|
||||
private suspend fun downloadChapterPages() = withContext(Dispatchers.IO) {
|
||||
tbtnlist.forEach { i ->
|
||||
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<ComicDlFragme
|
||||
}
|
||||
}
|
||||
|
||||
private fun onZipDownloadFailure(index: Int, message: String) {
|
||||
private suspend fun onZipDownloadFailure(index: Int, message: String) = withContext(Dispatchers.Main) {
|
||||
tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error)
|
||||
tbtnlist[index].isEnabled = true
|
||||
Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败: $message", Toast.LENGTH_SHORT).show()
|
||||
updateProgressBar()
|
||||
}
|
||||
@@ -314,12 +323,16 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
|
||||
//ObjectAnimator.ofFloat(dlsdwn, "alpha", 0.9f, 0.3f).setDuration(233).start()
|
||||
ObjectAnimator.ofFloat(that?.dlsdwn, "translationX", 0f, cdwnWidth.toFloat() * 0.9f).setDuration(233).start()
|
||||
}
|
||||
private fun addTbtn(data: Array<String>){
|
||||
addTbtn(data[0], data[1], data[2], data[3])
|
||||
urlArray += data[3]
|
||||
private suspend fun addButtons(chapters: Array<ChapterStructure>, 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<ComicDlFragme
|
||||
//tbv.tbtn.hint = caption
|
||||
tbv.tbtn.caption = caption
|
||||
tbv.tbtn.layoutParams.width = btnw
|
||||
val zipf = CMApi.getZipFile(that!!.context?.getExternalFilesDir(""), comicName, caption, title)
|
||||
Log.d("MyCD", "Get zipf: $zipf")
|
||||
ViewMangaActivity.fileArray += zipf
|
||||
if (zipf.exists()) {
|
||||
tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
tbv.tbtn.isChecked = false
|
||||
}
|
||||
|
||||
that?.ltbtn?.ltbtn?.addView(tbv)
|
||||
that?.ltbtn?.invalidate()
|
||||
tbv.tbtn.setOnClickListener {
|
||||
if (zipf.exists() && !multiSelect) {
|
||||
it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
it.tbtn.isChecked = false
|
||||
ViewMangaActivity.zipFile = zipf
|
||||
ViewMangaActivity.dlHandler = this
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
val intent = Intent(that?.context, ViewMangaActivity::class.java)
|
||||
intent.putExtra("urlArray", urlArray).putExtra("callFrom", "zipFirst")
|
||||
that?.startActivity(intent)
|
||||
} else {
|
||||
it.tbtn.setBackgroundResource(R.drawable.toggle_button)
|
||||
if (it.tbtn.isChecked) that?.tdwn?.text = "$dldChapter/${++checkedChapter}"
|
||||
else that?.tdwn?.text = "$dldChapter/${--checkedChapter}"
|
||||
}
|
||||
}
|
||||
tbv.tbtn.setOnLongClickListener {
|
||||
if (zipf.exists()) {
|
||||
toolsBox.buildInfo("确认删除${if (multiSelect) "这些" else "本"}章节?",
|
||||
"该操作将不可撤销",
|
||||
"确定",
|
||||
null,
|
||||
"取消",
|
||||
{
|
||||
Thread {
|
||||
obtainMessage(7, it.tbtn.index, 0, zipf).sendToTarget()
|
||||
}.start()
|
||||
})
|
||||
}else{
|
||||
toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定",
|
||||
null, "取消", {
|
||||
ViewMangaActivity.zipFile = null
|
||||
ViewMangaActivity.dlHandler = this
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
|
||||
val intent = Intent(that?.context, ViewMangaActivity::class.java)
|
||||
intent.putExtra("urlArray", urlArray)
|
||||
that?.startActivity(intent)
|
||||
}, null, null
|
||||
)
|
||||
withContext(Dispatchers.IO) {
|
||||
val zipf = CMApi.getZipFile(that!!.context?.getExternalFilesDir(""), comicName, caption, title)
|
||||
Log.d("MyCD", "Get zipf: $zipf")
|
||||
ViewMangaActivity.fileArray += zipf
|
||||
if (zipf.exists()) withContext(Dispatchers.Main) {
|
||||
tbv.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
tbv.tbtn.isChecked = false
|
||||
}
|
||||
tbv.tbtn.setOnClickListener {
|
||||
if (zipf.exists() && !multiSelect) {
|
||||
it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
|
||||
it.tbtn.isChecked = false
|
||||
ViewMangaActivity.zipFile = zipf
|
||||
ViewMangaActivity.dlHandler = this@ComicDlHandler
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
val intent = Intent(that?.context, ViewMangaActivity::class.java)
|
||||
intent.putExtra("urlArray", urlArray).putExtra("callFrom", "zipFirst")
|
||||
that?.startActivity(intent)
|
||||
} else {
|
||||
it.tbtn.setBackgroundResource(R.drawable.toggle_button)
|
||||
if (it.tbtn.isChecked) that?.tdwn?.text = "$dldChapter/${++checkedChapter}"
|
||||
else that?.tdwn?.text = "$dldChapter/${--checkedChapter}"
|
||||
}
|
||||
}
|
||||
tbv.tbtn.setOnLongClickListener {
|
||||
if (zipf.exists()) {
|
||||
toolsBox.buildInfo("确认删除${if (multiSelect) "这些" else "本"}章节?",
|
||||
"该操作将不可撤销",
|
||||
"确定",
|
||||
null,
|
||||
"取消",
|
||||
{
|
||||
obtainMessage(7, it.tbtn.index, 0, zipf).sendToTarget()
|
||||
})
|
||||
} else {
|
||||
toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定",
|
||||
null, "取消", {
|
||||
ViewMangaActivity.zipFile = null
|
||||
ViewMangaActivity.dlHandler = this@ComicDlHandler
|
||||
ViewMangaActivity.position = it.tbtn.index
|
||||
dl?.show()
|
||||
|
||||
val intent = Intent(that?.context, ViewMangaActivity::class.java)
|
||||
intent.putExtra("urlArray", urlArray)
|
||||
that?.startActivity(intent)
|
||||
}, null, null
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun analyzeOldStructure() = Thread{
|
||||
private suspend fun analyzeOldStructure() = withContext(Dispatchers.IO) {
|
||||
Gson().fromJson(json?.reader(), Array<ComicStructureOld>::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<ComicDlFragme
|
||||
chapter.url.substringAfterLast('/')
|
||||
)?:""
|
||||
Log.d("MyCD", "Generate new url: $newUrl")
|
||||
obtainMessage(10, arrayOf(chapter.name, "", group.name, newUrl)).sendToTarget()
|
||||
addButton(chapter.name, "", group.name, newUrl)
|
||||
urlArray += newUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,12 @@ class DownloadFragment: NoBackRefreshFragment(R.layout.fragment_download) {
|
||||
private fun callDownloadFragment(jsonFile: File, isNew: Boolean = false){
|
||||
val bundle = Bundle()
|
||||
Log.d("MyDF", "Call dl and is new: $isNew")
|
||||
bundle.putBoolean(if(isNew) "loadJson" else "callFromOldDL", true)
|
||||
if(isNew) {
|
||||
bundle.putString("loadJson", jsonFile.readText())
|
||||
} else {
|
||||
bundle.putBoolean("callFromOldDL", true)
|
||||
}
|
||||
bundle.putString("name", jsonFile.parentFile?.name?:"Null")
|
||||
ComicDlFragment.json = jsonFile.readText()
|
||||
Log.d("MyDF", "root view: $rootView")
|
||||
Log.d("MyDF", "action_nav_download_to_nav_group")
|
||||
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_download_to_nav_group, bundle)
|
||||
|
||||
@@ -169,9 +169,8 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
|
||||
private fun callDownloadFragment(name: String){
|
||||
val bundle = Bundle()
|
||||
Log.d("MyNDF", "Call dl and is new.")
|
||||
bundle.putBoolean("loadJson", true)
|
||||
bundle.putString("loadJson", File(File(extDir, name), "info.json").readText())
|
||||
bundle.putString("name", name)
|
||||
ComicDlFragment.json = File(File(extDir, name), "info.json").readText()
|
||||
Log.d("MyNDF", "root view: $rootView")
|
||||
Log.d("MyNDF", "action_nav_new_download_to_nav_group")
|
||||
Navigate.safeNavigateTo(findNavController(), R.id.action_nav_new_download_to_nav_group, bundle)
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageButton
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -22,12 +23,15 @@ import kotlinx.android.synthetic.main.card_book_plain.view.*
|
||||
import kotlinx.android.synthetic.main.fragment_home.*
|
||||
import kotlinx.android.synthetic.main.line_word.view.*
|
||||
import kotlinx.android.synthetic.main.viewpage_horizonal.view.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import top.fumiama.copymanga.MainActivity
|
||||
import top.fumiama.copymanga.MainActivity.Companion.ime
|
||||
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
|
||||
import top.fumiama.copymanga.json.BookListStructure
|
||||
import top.fumiama.copymanga.template.general.NoBackRefreshFragment
|
||||
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.GlideHideLottieViewListener
|
||||
import top.fumiama.copymanga.tools.ui.Navigate
|
||||
@@ -44,15 +48,15 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
|
||||
if(isFirstInflate) {
|
||||
val tb = mainWeakReference?.get()?.toolsBox
|
||||
val netInfo = tb?.netInfo
|
||||
if(netInfo != null && netInfo != tb.transportStringNull && netInfo != tb.transportStringError) Thread {
|
||||
val l = MainActivity.member?.refreshAvatar()
|
||||
if (l?.code != 200) {
|
||||
mainWeakReference?.get()?.runOnUiThread {
|
||||
Toast.makeText(context, "${getString(R.string.login_get_avatar_failed)}: 代码${l?.code}, 信息: ${l?.message}", Toast.LENGTH_SHORT).show()
|
||||
if(netInfo != null && netInfo != tb.transportStringNull && netInfo != tb.transportStringError)
|
||||
MainActivity.member?.apply { lifecycleScope.launch {
|
||||
info().let { l ->
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<HomeFragment>) : 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<HomeFragment>) : 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<HomeFragment>) : 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<ComicStructure>()
|
||||
for((i, topic) in it.withIndex()){
|
||||
@@ -135,7 +132,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateRec(){
|
||||
private suspend fun inflateRec() {
|
||||
index?.results?.recComics?.list?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
@@ -150,7 +147,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateRank(){
|
||||
private suspend fun inflateRank(){
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
index?.results?.rankDayComics?.list?.let {
|
||||
for((i, book) in it.withIndex()){
|
||||
@@ -175,7 +172,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateHot(){
|
||||
private suspend fun inflateHot(){
|
||||
index?.results?.hotComics?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
@@ -186,7 +183,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateNew(){
|
||||
private suspend fun inflateNew(){
|
||||
index?.results?.newComics?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
@@ -201,7 +198,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateFinish(){
|
||||
private suspend fun inflateFinish(){
|
||||
index?.results?.finishComics?.list?.let {
|
||||
var comics = arrayOf<ComicStructure>()
|
||||
for((i, rec) in it.withIndex()){
|
||||
@@ -216,20 +213,24 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : 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<HomeFragment>) : 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<HomeFragment>) : 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<ComicStructure>, finish: Boolean = false, isTopic: Boolean = false, onClick: (() -> Unit)? = null): Int{
|
||||
private suspend fun allocateLine(
|
||||
title: String, iconResId: Int, comics: Array<ComicStructure>,
|
||||
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<HomeFragment>) : 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<ComicStructure>, finish: Boolean, isTopic: Boolean){
|
||||
private suspend fun scanCards(v: View, comics: Array<ComicStructure>, finish: Boolean, isTopic: Boolean) = withContext(Dispatchers.IO) {
|
||||
var id = v.rc1.id
|
||||
var card = v.findViewById<ConstraintLayout>(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<HomeFragment>) : 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<HomeFragment>) : AutoDownloadH
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>) : 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)
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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<LoginInfoStructure>(
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////有效性判断////////////////////////////////
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/book_bg_card_padding">
|
||||
|
||||
<include
|
||||
@@ -37,7 +37,7 @@
|
||||
android:id="@+id/lbitb"
|
||||
layout="@layout/line_booktandb"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/nav_header_height"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="2"
|
||||
app:layout_constraintStart_toEndOf="@+id/lbc"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE resources [
|
||||
<!ENTITY hosturl "api.copymanga.tv">
|
||||
]>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="app_name">拷贝漫画</string>
|
||||
|
||||
<string name="action_settings">设定</string>
|
||||
@@ -81,7 +81,7 @@
|
||||
<string name="shelfOperateApiUrl">https://%1$s/api/v3/member/collect/comic</string>
|
||||
|
||||
<string name="imgProxyApiUrl">https://copymanga.azurewebsites.net/api/img?code=%1$s&url=%2$s</string>
|
||||
<string name="imgProxyApiPrefix">https://hi77-overseas.mangafuna.xyz/</string>
|
||||
<string name="imgProxyApiRegex" tools:ignore="TypographyDashes">^https://[0-9a-z-]+\.mangafuna\.xyz/</string>
|
||||
<string name="imgProxyKeyID">settings_cat_net_et_img_proxy_code</string>
|
||||
<!--
|
||||
<string name="apiProxyApiUrl">https://copymanga.azurewebsites.net/api/api?url=%1$s</string>
|
||||
@@ -170,7 +170,7 @@
|
||||
<string name="login_null_username">用户名为空</string>
|
||||
<string name="login_null_pwd">密码为空</string>
|
||||
<string name="login_get_conn_failed">登录失败</string>
|
||||
<string name="login_get_avatar_failed">刷新头像失败</string>
|
||||
<string name="login_get_avatar_failed">恢复登录失败</string>
|
||||
<string name="login_restart_to_apply">重启应用以彻底退出登录</string>
|
||||
|
||||
<string name="old_download_card_name">前往旧版下载</string>
|
||||
|
||||
Reference in New Issue
Block a user