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