1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-09 17:50:28 +08:00

2.0.beta6

1. 修复漫画封面为空导致的主页闪退
2. 增加详情页导航到作者、标签
3. 增加阅览缓存、音量键页、双页切分
4. 优化卷轴模式、下载逻辑
This commit is contained in:
fumiama
2021-05-14 22:34:29 +08:00
parent c366d62098
commit 16dd13e902
21 changed files with 665 additions and 352 deletions

View File

@@ -0,0 +1,75 @@
package top.fumiama.copymanga.template.ui
import android.animation.ObjectAnimator
import android.view.View
import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_finish.*
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi
open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) {
val sortWay = listOf("datetime_updated", "-datetime_updated", "popular", "-popular")
var sortValue = 0
override fun getApiUrl() =
getString(api).let {
String.format(
it,
page * 21,
sortWay[sortValue]
)
}
override fun setListeners() {
super.setListeners()
setUpdate(line_finish_time)
setHot(line_finish_pop)
}
override fun onLoadFinish() {
super.onLoadFinish()
mainWeakReference?.get()?.runOnUiThread {
mypl.visibility = View.GONE
}
}
open fun setUpdate(that: View) {
that.apply {
apt.setText(R.string.menu_update_time)
setOnClickListener {
sortValue = if(apim.rotation == 0f) {
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
1
}else{
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread{
Thread.sleep(400)
mh?.sendEmptyMessage(4)
}.start()
}
}
}
open fun setHot(that: View) {
that.apply {
apt.setText(R.string.menu_hot)
setOnClickListener {
sortValue = if (apim.rotation == 0f) {
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
1
} else {
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread {
Thread.sleep(400)
mh?.sendEmptyMessage(4)
}.start()
}
}
}
}

View File

@@ -0,0 +1,36 @@
package top.fumiama.copymanga.template.ui
import android.os.Bundle
import kotlinx.android.synthetic.main.app_bar_main.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
@ExperimentalStdlibApi
open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav) {
private var theme = ""
override fun getApiUrl() =
getString(api).let {
String.format(
it,
page * 21,
sortWay[sortValue],
theme
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.apply {
getString("path")?.apply { theme = this }
getString("name")?.apply {
mainWeakReference?.get()?.toolbar?.title = this
}
}
}
override fun onResume() {
super.onResume()
arguments?.getString("name")?.apply {
mainWeakReference?.get()?.toolbar?.title = this
}
}
}

View File

@@ -3,7 +3,6 @@ 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.security.SecureRandom
@@ -25,24 +24,31 @@ object DownloadTools {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)
}
private fun getConnection(url: String?, method: String = "GET") =
url?.let {
val connection = URL(url).openConnection() as HttpURLConnection
connection.requestMethod = method
connection.connectTimeout = 20000
connection.readTimeout = 20000
connection
}
fun getHttpContent(Url: String, refer: String? = null, ua: String? = null): ByteArray? {
Log.d("Mydl", "getHttp: $Url")
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
val connection = URL(Url).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 20000
connection.readTimeout = 20000
refer?.let { connection.setRequestProperty("referer", it) }
connection.setRequestProperty("source", "copyApp")
connection.setRequestProperty("webp", "1")
connection.setRequestProperty("region", "1")
connection.setRequestProperty("platform", "3")
ua?.let { connection.setRequestProperty("User-agent", it) }
getConnection(Url)?.apply {
refer?.let { setRequestProperty("referer", it) }
setRequestProperty("source", "copyApp")
setRequestProperty("webp", "1")
setRequestProperty("region", "1")
setRequestProperty("platform", "3")
ua?.let { setRequestProperty("User-agent", it) }
ret = connection.inputStream.readBytes()
connection.disconnect()
ret = inputStream.readBytes()
disconnect()
}
} catch (ex: Exception) {
ex.printStackTrace()
}
@@ -56,78 +62,17 @@ object DownloadTools {
null
}
}
fun downloadUsingUrlRet(Url: String?, f: File): Boolean {
Log.d("Mydl", "Ret Get Url: $Url, File: $f")
val task = FutureTask(Callable {
try {
val connection = URL(Url).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 20000
connection.readTimeout = 20000
connection.setRequestProperty("source", "copyApp")
connection.setRequestProperty("webp", "1")
connection.setRequestProperty("region", "1")
connection.setRequestProperty("platform", "3")
if (f.exists()) f.delete()
else f.parentFile?.mkdirs()
f.parentFile?.let {
if (!it.canRead()) it.setReadable(true)
if (!it.canWrite()) it.setWritable(true)
}
connection.inputStream.buffered().copyTo(f.outputStream())
connection.disconnect()
return@Callable true
} catch (ex: Exception) {
ex.printStackTrace()
return@Callable false
}
})
Thread(task).start()
return try {
task.get()
} catch (ex: Exception) {
ex.printStackTrace()
false
}
}
fun downloadUsingUrl(Url: String?, f: File, refer: String? = null) {
Log.d("Mydl", "Get Url: $Url, File: $f")
Thread(Runnable {
try {
val connection = URL(Url).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 20000
connection.readTimeout = 20000
refer?.let { connection.setRequestProperty("referer", it) }
if (f.exists()) f.delete()
else f.parentFile?.mkdirs()
f.parentFile?.let {
if (!it.canRead()) it.setReadable(true)
if (!it.canWrite()) it.setWritable(true)
}
connection.inputStream.buffered().copyTo(f.outputStream())
connection.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
}).start()
}
fun getHttpContent(Url: String, refer: String? = null): ByteArray? {
Log.d("Mydl", "getHttp: $Url")
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
val connection = URL(Url).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 20000
connection.readTimeout = 20000
refer?.let { connection.setRequestProperty("referer", it) }
val connection = getConnection(Url)
refer?.let { connection?.setRequestProperty("referer", it) }
ret = connection.inputStream.readBytes()
connection.disconnect()
ret = connection?.inputStream?.readBytes()
connection?.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
@@ -141,4 +86,55 @@ object DownloadTools {
null
}
}
fun getHttpContent(Url: String, readSize: Int? = null, refer: String? = "https://api.copymanga.com"): ByteArray? {
Log.d("Mydl", "getHttp: $Url")
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
val connection = getConnection(Url)
refer?.let { connection?.setRequestProperty("referer", it) }
val ci = connection?.inputStream
if(readSize != null) {
ret = ByteArray(readSize)
ci?.read(ret, 0, readSize)
} else ret = ci?.readBytes()
ci?.close()
connection?.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
return@Callable ret
})
Thread(task).start()
return try {
task.get()
} catch (ex: Exception) {
ex.printStackTrace()
null
}
}
fun touch(url: String?, refer: String? = "https://www.dmzj1.com"): FutureTask<ByteArray?>? =
url?.let {
Log.d("Mydl", "touchHttp: $it")
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
val connection = getConnection(it)
refer?.let { connection?.setRequestProperty("referer", it) }
val ci = connection?.inputStream
ret = ci?.readBytes()
ci?.close()
connection?.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
return@Callable ret
})
Thread(task).start()
task
}
}

View File

@@ -19,6 +19,7 @@ class MangaDlTools {
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"
@@ -72,6 +73,8 @@ class MangaDlTools {
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
@@ -89,7 +92,6 @@ class MangaDlTools {
if (!s && tryTimes <= 0) succeed = false
onDownloadedListener?.handleMessage(s, i + 1)
zip.flush()
if (exit) break
}
zip.close()
onDownloadedListener?.handleMessage(succeed)

View File

@@ -5,6 +5,7 @@ import android.util.Log
import android.view.Menu
import android.view.View
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.app_bar_main.*
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.template.general.NoBackRefreshFragment
@@ -28,7 +29,10 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
override fun onResume() {
super.onResume()
mainWeakReference?.get()?.menuMain?.let { setMenuVisible(it) }
mainWeakReference?.get()?.apply {
menuMain?.let { setMenuVisible(it) }
toolbar.title = bookHandler.book?.results?.comic?.name
}
}
override fun onDestroy() {
@@ -37,6 +41,11 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
bookHandler.destroy()
}
override fun onPause() {
super.onPause()
mainWeakReference?.get()?.menuMain?.let { setMenuInvisible(it) }
}
private fun setMenuInvisible(menu: Menu){
menu.findItem(R.id.action_download)?.isVisible = false
}

View File

@@ -17,6 +17,7 @@ import kotlinx.android.synthetic.main.fragment_book.*
import kotlinx.android.synthetic.main.line_2chapters.view.*
import kotlinx.android.synthetic.main.line_bookinfo.*
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 top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
@@ -52,7 +53,7 @@ class BookHandler(that: WeakReference<BookFragment>, path: String)
1 -> setCover()
2 -> setTexts()
3 -> fbibinfo?.let { setInfoHeight(it) }
//4 -> setThemes()
4 -> setThemes()
5 -> setOverScale()
6 -> endSetLayouts()
}
@@ -147,44 +148,60 @@ class BookHandler(that: WeakReference<BookFragment>, path: String)
}
}
private fun setThemes(){
book?.results?.groups?.let {
val keyIterator = it.keys.iterator()
for(i in 0 until it.size){
if(i % 2 == 0){
that?.fbl?.addView(if(i < it.size - 1){
val line = that.layoutInflater.inflate(R.layout.line_2chapters, that.fbl, false)
val leftKey = keyIterator.next()
line?.l2cl?.lct?.text = it[leftKey]?.name
line?.l2cl?.setOnClickListener { _->
loadVolume(it[leftKey]?.path_word?:"null")
private fun setTheme(caption: String, themeStructure: Array<ThemeStructure>, nav: Int) {
that?.apply {
val t = layoutInflater.inflate(R.layout.line_caption, fbl, false)
t.tcptn.text = caption
fbl.addView(t)
fbl.addView(layoutInflater.inflate(R.layout.div_h, fbl, false))
}
var line: View? = null
val last = themeStructure.size - 1
themeStructure.onEachIndexed { i, it ->
if(line == null) {
if(i == last) {
line = that?.layoutInflater?.inflate(R.layout.line_chapter, that.fbl, false)
line?.lcc?.apply {
lct.text = it.name
setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav)
}
val rightKey = keyIterator.next()
line?.l2cr?.lct?.text = it[rightKey]?.name
line?.l2cr?.setOnClickListener { _->
loadVolume(it[rightKey]?.path_word?:"null")
}
that?.fbl?.addView(line)
} else {
line = that?.layoutInflater?.inflate(R.layout.line_2chapters, that.fbl, false)
line?.l2cl?.apply {
lct.text = it.name
setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav)
}
line
}else{
//Log.d("MyBH", "Add chapter: ${vol[i].volume_name}")
val line = that.layoutInflater.inflate(R.layout.line_chapter, that.fbl, false)
val key = keyIterator.next()
line?.lct?.text = it[key]?.name
line?.lcc?.setOnClickListener { _->
loadVolume(it[key]?.path_word?:"null")
}
line
})
}
}
} else line?.l2cr?.apply {
lct.text = it.name
setOnClickListener { _ ->
loadVolume(it.name, it.path_word, nav)
}
that?.fbl?.addView(line)
line = null
}
}
}
private fun loadVolume(gpw: String){
private fun setThemes(){
that?.apply {
book?.results?.comic?.apply {
author?.let { setTheme(getString(R.string.author), it, R.id.action_nav_book_to_nav_author) }
theme?.let { setTheme(getString(R.string.caption), it, R.id.action_nav_book_to_nav_caption) }
}
}
}
private fun loadVolume(name: String, path: String, nav: Int){
Log.d("MyBH", "start to load chapter")
val bundle = Bundle()
bundle.putString("group", gpw)
book?.results?.comic?.path_word?.let { bundle.putString("path", it) }
that?.rootView?.let { Navigation.findNavController(it).navigate(R.id.action_nav_book_to_nav_chapter, bundle) }
bundle.putString("name", name)
bundle.putString("path", path)
that?.rootView?.let { Navigation.findNavController(it).navigate(nav, bundle) }
}
}

View File

@@ -0,0 +1,7 @@
package top.fumiama.copymanga.ui.cardflow.author
import top.fumiama.copymanga.template.ui.ThemeCardFlow
import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi
class AuthorFragment : ThemeCardFlow(R.string.authorApiUrl, R.id.action_nav_author_to_nav_book)

View File

@@ -0,0 +1,7 @@
package top.fumiama.copymanga.ui.cardflow.caption
import top.fumiama.copymanga.template.ui.ThemeCardFlow
import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi
class CaptionFragment : ThemeCardFlow(R.string.captionApiUrl, R.id.action_nav_caption_to_nav_book)

View File

@@ -1,77 +1,7 @@
package top.fumiama.copymanga.ui.cardflow.finish
import android.animation.ObjectAnimator
import android.view.View
import kotlinx.android.synthetic.main.anchor_popular.view.*
import kotlinx.android.synthetic.main.line_finish.*
import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.template.ui.StatusCardFlow
import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep
@ExperimentalStdlibApi
class FinishFragment : InfoCardLoader(R.layout.fragment_finish, R.id.action_nav_finish_to_nav_book) {
private val sortWay = listOf("datetime_updated", "-datetime_updated", "popular", "-popular")
private var sortValue = 0
override fun getApiUrl() =
getString(R.string.finishApiUrl).let {
String.format(
it,
page * 21,
sortWay[sortValue]
)
}
override fun setListeners() {
super.setListeners()
setUpdate()
setHot()
}
override fun onLoadFinish() {
super.onLoadFinish()
mainWeakReference?.get()?.runOnUiThread {
mypl.visibility = View.GONE
}
}
private fun setUpdate() {
line_finish_time.apply {
apt.setText(R.string.menu_update_time)
setOnClickListener {
sortValue = if(apim.rotation == 0f) {
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
1
}else{
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread{
sleep(400)
mh?.sendEmptyMessage(4)
}.start()
}
}
}
private fun setHot() {
line_finish_pop.apply {
apt.setText(R.string.menu_hot)
setOnClickListener {
sortValue = if (apim.rotation == 0f) {
ObjectAnimator.ofFloat(apim, "rotation", 0f, 180f).setDuration(233).start()
1
} else {
ObjectAnimator.ofFloat(apim, "rotation", 180f, 0f).setDuration(233).start()
0
}
Thread {
sleep(400)
mh?.sendEmptyMessage(4)
}.start()
}
}
}
}
class FinishFragment : StatusCardFlow(R.string.finishApiUrl, R.id.action_nav_finish_to_nav_book)

View File

@@ -60,7 +60,6 @@ class ComicDlHandler(looper: Looper, that: WeakReference<ComicDlFragment>, priva
private var checkedChapter = 0
private var dldChapter = 0
private var haveDlStarted = false
private var canDl = false
private var tbtnlist: Array<ChapterToggleButton> = arrayOf()
private var tbtncnt = 0
private var isNewTitle = false
@@ -215,10 +214,12 @@ class ComicDlHandler(looper: Looper, that: WeakReference<ComicDlFragment>, priva
setProgress2(dldChapter * 100 / checkedChapter, 233)
}
private fun updateProgressBar(pageNow: Int, size: Int) {
val delta = 100 / checkedChapter
val start = dldChapter * delta
val now = pageNow * delta / size
setProgress2(start + now, 64)
if(checkedChapter > 0) {
val delta = 100 / checkedChapter
val start = dldChapter * delta
val now = pageNow * delta / size
setProgress2(start + now, 64)
}
}
private fun setProgress2(end: Int, duration: Long) {
ObjectAnimator.ofInt(
@@ -259,10 +260,10 @@ class ComicDlHandler(looper: Looper, that: WeakReference<ComicDlFragment>, priva
else if(checkedChapter == 0) hideDlCard()
else{
that.pdwn.progress = 0
if (canDl || checkedChapter == 0) canDl = false
if(haveDlStarted && checkedChapter != 0) mangaDlTools.wait = !mangaDlTools.wait
else {
haveDlStarted = true
canDl = true
mangaDlTools.wait = false
Thread{
sendEmptyMessage(9) //set dl card color to green
downloadMangas()
@@ -291,16 +292,8 @@ class ComicDlHandler(looper: Looper, that: WeakReference<ComicDlFragment>, priva
private fun downloadMangas(){
for (i in tbtnlist) {
if (i.isChecked) downloadChapterPages(i)
if (!canDl) {
checkedChapter -= dldChapter
dldChapter = 0
break
}
}
if (canDl) {
haveDlStarted = false
canDl = false
}
haveDlStarted = false
}
private fun downloadChapterPages(i: ChapterToggleButton) {

View File

@@ -310,7 +310,9 @@ class HomeHandler(that: WeakReference<HomeFragment>) : AutoDownloadHandler(
private fun setCards(cv: CardView, pw: String, name: String, img: String, isFinal: Boolean, isTopic: Boolean) {
cv.tic.text = name
homeF?.let {
Glide.with(it).load(GlideUrl(img, CMApi.myGlideHeaders)).timeout(20000).into(cv.imic)
if(img.startsWith("http")) {
Glide.with(it).load(GlideUrl(img, CMApi.myGlideHeaders)).timeout(20000).into(cv.imic)
}
}
if (isFinal) cv.sgnic.visibility = View.VISIBLE
cv.setOnClickListener {

View File

@@ -21,7 +21,7 @@ class PagesManager(w: WeakReference<ViewMangaActivity>) {
toPage(v?.r2l!=true)
}
private fun judgePrevious() = v?.pageNum?:0 > 1
private fun judgeNext() = v?.pageNum?:0 < v?.count?:0
private fun judgeNext() = v?.pageNum?:0 < v?.realCount?:0
@ExperimentalStdlibApi
fun toPage(goNext:Boolean){
if (v?.clicked == false) {

View File

@@ -78,19 +78,19 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
}
4 -> {
val simg = msg.obj as ScaleImageView
wv.get()?.loadImgOn(simg, msg.arg1)
simg.setHeight2FitImgWidth()
if(msg.arg2 == 1) sendEmptyMessage(8)
wv.get()?.loadImgOn(simg, msg.arg1, msg.arg2)
//simg.setHeight2FitImgWidth()
//if(msg.arg2 == 1) sendEmptyMessage(8)
}
5 -> wv.get()?.clearImgOn(msg.obj as ScaleImageView)
6 -> wv.get()?.prepareLastPage(msg.arg1, msg.arg2)
7 -> dl?.show()
8 -> Thread{
sleep(233)
sendEmptyMessage(13)
}.start()
9 -> loadThread(msg.arg1)
10 -> loadThread()
sleep(233)
sendEmptyMessage(13)
}.start()
9 -> loadScrollMode(msg.arg1)
10 -> loadScrollMode()
11 -> loadImgsIntoLine(msg.arg1)
12 -> loadImgsIntoLine()
13 -> {
@@ -98,10 +98,12 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
wv.get()?.restorePN()
}
14 -> {
val item = (pn - 1) / (wv.get()?.verticalLoadMaxCount?:40) * (wv.get()?.verticalLoadMaxCount?:40)
loadThread(item)
val item = (pn - 1) / (wv.get()?.verticalLoadMaxCount?:20) * (wv.get()?.verticalLoadMaxCount?:20)
loadScrollMode(item)
Log.d("MyVMH", "Load page from $item")
}
15 -> dl?.hide()
//16 -> wv.get()?.prepareItems()
22 -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netinfo
}
}
@@ -128,7 +130,10 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
fun loadFromFile(file: File): Boolean {
return try {
val jsonFile = File(file.parentFile, "${file.nameWithoutExtension}.json")
if(jsonFile.exists()) manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java)
if(jsonFile.exists()) {
manga = Gson().fromJson(jsonFile.reader(), Chapter2Return::class.java)
prepareManga()
}
else{
manga = Chapter2Return()
manga?.let {
@@ -137,10 +142,12 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
it.results.comic.name = file.parentFile?.name
it.results.chapter = ChapterWithContent()
it.results.chapter.name = file.nameWithoutExtension
it.results.chapter.size = countZipEntries(file)
wv.get()?.countZipEntries { c ->
it.results.chapter.size = c
prepareManga()
}
}
}
prepareManga()
true
}catch (e: Exception){
e.printStackTrace()
@@ -149,23 +156,6 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
}
}
private fun countZipEntries(file: File): Int{
var count = 0
try {
val zip = ZipInputStream(file.inputStream().buffered())
var entry = zip.nextEntry
while (entry != null) {
if (!entry.isDirectory) count++
entry = zip.nextEntry
}
zip.closeEntry()
zip.close()
} catch (e: Exception) {
wv.get()?.toolsBox?.toastError("统计zip图片数错误!")
}
return count
}
@ExperimentalStdlibApi
private fun prepareManga(){
comicName = manga?.results?.comic?.name
@@ -174,29 +164,33 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
wv.get()?.initManga()
wv.get()?.vprog?.visibility = View.GONE
}
private fun loadImgsIntoLine(item: Int = (wv.get()?.currentItem?:0), maxCount: Int = (wv.get()?.verticalLoadMaxCount?:40)){
Log.d("MyVMH", "Fun: loadImgsIntoLine($item)")
val count = wv.get()?.count?.minus(1)?:0
val notFull = item + maxCount > count
val loadCount = (if(notFull) count - item else maxCount) - 1
Log.d("MyVMH", "loadCount: $loadCount")
if(loadCount >= 0) for(i in 0..loadCount) obtainMessage(4,item + i, if(i == loadCount - 1)1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget()
else sendEmptyMessage(8)
if(notFull) obtainMessage(6, loadCount + 1, maxCount).sendToTarget()
}
private fun loadImgsIntoLine(item: Int = (wv.get()?.currentItem?:0), maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)) /*= Thread*/{
Log.d("MyVMH", "Fun: loadImgsIntoLine($item, $maxCount)")
wv.get()?.realCount?.let { count ->
if(count > 0){
val notFull = item + maxCount > count
val loadCount = (if(notFull) count - item else maxCount) - 1
Log.d("MyVMH", "count: $count, loadCount: $loadCount, notFull: $notFull")
if(loadCount >= 0) for(i in 0..loadCount) obtainMessage(4,item + i, if(i == loadCount - 1) 1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget()
else sendEmptyMessage(8)
if(notFull) obtainMessage(6, loadCount + 1, maxCount).sendToTarget()
wv.get()?.updateSeekBar()
}
}
}//.start()
private fun loadThread() = Thread{
private fun loadScrollMode() {
sendEmptyMessage(7)
//sleep(233)
sendEmptyMessage(12)
}.start()
}
private fun loadThread(item: Int) = Thread{
private fun loadScrollMode(item: Int) {
sendEmptyMessage(7)
//sleep(233)
Log.d("MyVMH", "loadImgsIntoLine($item)")
obtainMessage(11, item, 0).sendToTarget()
}.start()
}
private fun showInfCard() {
Log.d("MyVMH", "Read info drawer delta: $delta")

View File

@@ -2,8 +2,10 @@ package top.fumiama.copymanga.ui.vm
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.app.Service
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.AudioManager
import android.os.Bundle
import android.os.Handler
import android.util.Log
@@ -14,6 +16,8 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import com.liaoinstan.springview.widget.SpringView
import kotlinx.android.synthetic.main.activity_viewmanga.*
import kotlinx.android.synthetic.main.line_header.view.*
@@ -28,6 +32,7 @@ import kotlinx.android.synthetic.main.widget_titlebar.view.*
import kotlinx.android.synthetic.main.widget_viewmangainfo.*
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.template.general.TitleActivityTemplate
import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.thread.TimeThread
@@ -35,8 +40,10 @@ import top.fumiama.copymanga.views.ScaleImageView
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream
import java.lang.ref.WeakReference
import java.util.*
import java.util.concurrent.FutureTask
import java.util.zip.ZipFile
class ViewMangaActivity : TitleActivityTemplate() {
@@ -49,23 +56,32 @@ class ViewMangaActivity : TitleActivityTemplate() {
//private var progressLog: PropertiesTools? = null
var scrollImages = arrayOf<ScaleImageView>()
//var zipFirst = false
private var useFullScreen = false
//private var useFullScreen = false
var r2l = true
var currentItem = 0
var verticalLoadMaxCount = 40
var verticalLoadMaxCount = 20
private var notUseVP = true
private var isVertical = false
private var q = 90
private val size get() = if(count / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else count % verticalLoadMaxCount
private var q = 100
private val size get() = if(realCount / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else realCount % verticalLoadMaxCount
var infoDrawerDelta = 0f
var pageNum: Int
get() = getPageNumber()
set(value) = setPageNumber(value)
//var pn = 0
private val isPnValid: Boolean get(){
if(pn == -2) pn = count
if(pn == -2) pn = realCount
return intent.getStringExtra("function") == "log" && pn > 0
}
private var tasks: Array<FutureTask<ByteArray?>?>? = null
private var destroy = false
private var cut = false
private var isCut = booleanArrayOf()
private var indexMap = intArrayOf()
private var volTurnPage = false
private var am: AudioManager? = null
private var pm: PagesManager? = null
val realCount get() = if(cut) indexMap.size else count
@ExperimentalStdlibApi
@SuppressLint("SetTextI18n")
@@ -76,17 +92,19 @@ class ViewMangaActivity : TitleActivityTemplate() {
//progressLog = PropertiesTools(File("$filesDir/progress/${chapter2Return?.results?.chapter?.comic_id}"))
//dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
//zipFirst = intent.getStringExtra("callFrom") == "zipFirst"
useFullScreen = p["useFullScreen"] != "true"
cut = p["useCut"] == "true"
r2l = p["r2l"] == "true"
verticalLoadMaxCount = if (p["verticalMax"] != "null") p["verticalMax"].toInt() else 20
isVertical = p["vertical"] == "true"
notUseVP = p["noVP"] == "true" || isVertical
//url = intent.getStringExtra("url")
handler = VMHandler(this, if(urlArray.isNotEmpty()) urlArray[position] else "")
if (p["quality"] != "null") q = p["quality"].toInt()
if (p["verticalMax"] != "null") verticalLoadMaxCount = p["verticalMax"].toInt()
tt = TimeThread(handler, 22)
tt.canDo = true
tt.start()
volTurnPage = p["volturn"] == "true"
am = getSystemService(Service.AUDIO_SERVICE) as AudioManager
Log.d("MyVM", "Now ZipFile is $zipFile")
try {
@@ -101,15 +119,33 @@ class ViewMangaActivity : TitleActivityTemplate() {
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if(useFullScreen) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R)
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
else {
window.setDecorFitsSystemWindows(false)
window.insetsController?.hide(WindowInsets.Type.statusBars())
//window.insetsController?.hide(WindowInsets.Type.navigationBars())
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R)
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
else {
window.setDecorFitsSystemWindows(false)
window.insetsController?.hide(WindowInsets.Type.statusBars())
//window.insetsController?.hide(WindowInsets.Type.navigationBars())
}
}
@ExperimentalStdlibApi
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
var flag = false
if(volTurnPage) when(keyCode) {
KeyEvent.KEYCODE_VOLUME_UP -> {
pm?.toPage(false)
flag = true
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
pm?.toPage(true)
flag = true
}
}
return if(flag) true else super.onKeyDown(keyCode, event)
}
private fun alertCellar() {
toolsBox.buildInfo("注意", "要使用使用流量观看吗?", "确定", null, "取消", {handler.startLoad()}, null, {finish()})
}
fun restorePN(){
@@ -121,30 +157,122 @@ class ViewMangaActivity : TitleActivityTemplate() {
sendProgress()
}
private fun preDownloadChapterPages() {
getImgUrlArray()?.let {
val mid = (if(pn in 1 until realCount) (if(cut) Math.abs(indexMap[pn]) else pn) else if(pn == -2 || pn >= realCount) it.size else 1) - 1
val left = if(isVertical && mid > verticalLoadMaxCount) (mid / verticalLoadMaxCount) * verticalLoadMaxCount else (mid-1)
val right = if(isVertical) (mid / verticalLoadMaxCount + 1) * verticalLoadMaxCount else mid
tasks = arrayOfNulls(it.size)
Thread{
for (i in right until it.size) {
if(destroy) break
tasks?.let { tasks ->
tasks[i] = DownloadTools.touch(it[i])
Thread.sleep(1000)
}
}
}.start()
Thread.sleep(500)
Thread{
for (i in left downTo 0) {
if(destroy) break
tasks?.let { tasks ->
tasks[i] = DownloadTools.touch(it[i])
Thread.sleep(1000)
}
}
}.start()
}
}
@ExperimentalStdlibApi
private fun doPrepareWebImg() {
getImgUrlArray()?.apply {
if(cut) {
handler.sendEmptyMessage(7) //showDl
isCut = BooleanArray(size)
val analyzedCnt = BooleanArray(size)
forEachIndexed{ i, it ->
if(it != null) {
Thread{
DownloadTools.getHttpContent(it, 1024)?.inputStream()?.let {
isCut[i] = canCut(it)
analyzedCnt[i] = true
}
}.start()
Thread.sleep(22)
}
}
while (analyzedCnt.count { it } != size) Thread.sleep(233)
isCut.forEachIndexed { index, b ->
Log.d("MyVM", "[$index] cut: $b")
indexMap += index+1
if(b) indexMap += -(index+1)
}
handler.sendEmptyMessage(15) //hideDl
}
count = size
runOnUiThread { prepareItems() }
preDownloadChapterPages()
}
}
@ExperimentalStdlibApi
fun initManga(){
prepareItems(count)
if (zipFile?.exists() != true) doPrepareWebImg()
else prepareItems()
if (!isVertical) restorePN()
}
@ExperimentalStdlibApi
private fun prepareImgFromWeb() {
handler.startLoad()
if(toolsBox.netinfo == "移动数据") alertCellar()
else handler.startLoad()
}
private fun canCut(inputStream: InputStream): Boolean{
val op = BitmapFactory.Options()
op.inJustDecodeBounds = true
BitmapFactory.decodeStream(inputStream, null, op)
Log.d("MyVM", "w: ${op.outWidth}, h: ${op.outHeight}")
return op.outWidth.toFloat() / op.outHeight.toFloat() > 1
}
@ExperimentalStdlibApi
fun countZipEntries(doWhenFinish : (count: Int) -> Unit) = Thread{
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 ->
val useCut = canCut(zip.getInputStream(it))
isCut += useCut
indexMap += i + 1
if (useCut) indexMap += -(i + 1)
Log.d("Myvm", "[$i] 分析: ${it.name}, cut: $useCut")
}
} catch (e: Exception) {
runOnUiThread { toolsBox.toastError("统计zip图片数错误!") }
}
runOnUiThread {
Log.d("Myvm", "开始加载控件")
doWhenFinish(count)
}
}.start()
private fun getPageNumber(): Int {
return if (r2l && !notUseVP) count - vp.currentItem
return if (r2l && !notUseVP) realCount - vp.currentItem
else (if (notUseVP) currentItem else vp.currentItem) + 1
}
private fun setPageNumber(num: Int) {
if (r2l && !notUseVP) vp.currentItem = count - num
if (r2l && !notUseVP) vp.currentItem = realCount - num
else if (notUseVP) {
if(isVertical){
currentItem = num - 1
val delta = currentItem % verticalLoadMaxCount
Log.d("MyVM", "Height: ${psivl.height}, scrollY: ${psivs.scrollY}")
if (!isInScroll || isInSeek) psivs.scrollY = psivl.height / size * delta
val offset = currentItem % verticalLoadMaxCount
Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}")
if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size
updateSeekBar()
}
else {
@@ -156,31 +284,86 @@ class ViewMangaActivity : TitleActivityTemplate() {
toolsBox.toastError("页数${currentItem}不合法")
}
}
} else vp.currentItem = num - 1
} else {
Log.d("MyVM", "Set vp current: ${num-1}")
var delta = num - 1 - vp.currentItem
if(delta >= 1) Thread{
while (delta-- > 0){
Thread.sleep(23)
runOnUiThread {
vp.currentItem++
}
}
}.start()
else if(delta <= -1) Thread{
while (delta++ < 0){
Thread.sleep(23)
runOnUiThread {
vp.currentItem--
}
}
}.start()
}
}
fun clearImgOn(imgView: ScaleImageView){
imgView.visibility = View.GONE
}
private fun getTempFile(position: Int) = File(cacheDir, "$position")
//private fun getTempFile(position: Int) = File(cacheDir, "$position")
private fun getImgUrl(position: Int) = handler.manga?.results?.chapter?.let {
it.contents[it.words.indexOf(position)].url
}
fun loadImgOn(imgView: ScaleImageView, position: Int){
if (zipFile?.exists() == true) imgView.setImageBitmap(getImgBitmap(position))
else if(isVertical) {
val f = getTempFile(position)
if(DownloadTools.downloadUsingUrlRet(getImgUrl(position), f))
imgView.setImageBitmap(BitmapFactory.decodeFile(f.path))
else Toast.makeText(this, "下载第${position}页失败", Toast.LENGTH_SHORT).show()
private fun getImgUrlArray() = handler.manga?.results?.chapter?.let{
val re = arrayOfNulls<String>(it.contents.size)
for(i in it.contents.indices) {
re[i] = getImgUrl(i)
}
re
}
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, isLast: Int = 0, useCut: Boolean, isLeft: Boolean){
val bitmap2load = if(useCut) cutBitmap(bitmap, isLeft) else bitmap
runOnUiThread {
imgView.setImageBitmap(bitmap2load)
if(isVertical){
imgView.setHeight2FitImgWidth()
if (isLast == 1) handler.sendEmptyMessage(8)
}
}
}
private fun loadImgUrlInto(imgView: ScaleImageView, url: String, isLast: Int = 0, useCut: Boolean, isLeft: Boolean){
Log.d("MyVM", "Load from adt: $url")
AutoDownloadThread(url) {
it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), isLast, useCut, isLeft) }
}.start()
}
fun loadImgOn(imgView: ScaleImageView, position: Int, isLast: Int = 0){
Log.d("MyVM", "Load img: $position")
val index2load = if(cut) Math.abs(indexMap[position]) -1 else position
val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[position] > 0
if (zipFile?.exists() == true) getImgBitmap(index2load)?.let {
loadImg(imgView, it, isLast, useCut, isLeft)
}
else {
val re = tasks?.get(index2load)
if (re != null) Thread{
val data = re.get()
if(data != null) {
loadImg(imgView, BitmapFactory.decodeByteArray(data, 0, data.size), isLast, useCut, isLeft)
Log.d("MyVM", "Load from task")
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, isLast, useCut, isLeft) }
}.start()
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, isLast, useCut, isLeft) }
}
else Glide.with(this)
.load(GlideUrl(getImgUrl(position), CMApi.myGlideHeaders))
.timeout(10000)
.into(imgView)
imgView.visibility = View.VISIBLE
}
@@ -190,7 +373,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
private fun initImgList(){
for (i in 0..39) {
for (i in 0 until verticalLoadMaxCount) {
val newImg = ScaleImageView(this)
scrollImages += newImg
psivl.addView(newImg)
@@ -202,24 +385,21 @@ class ViewMangaActivity : TitleActivityTemplate() {
handler.dl?.hide()
}
private fun getImgBitmap(position: Int): Bitmap? {
Log.d("MyVM", "Get bitmap @$position, count is $count")
if (position >= count || position < 0) return null
else {
private fun getImgBitmap(position: Int): Bitmap? =
if (position >= count || position < 0) null
else try {
val zip = ZipFile(zipFile)
if (q == 100) return BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
else {
val out = ByteArrayOutputStream()
try {
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))
} catch (e: Exception) {
e.printStackTrace()
return null
}?.compress(Bitmap.CompressFormat.JPEG, q, out)
return BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
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}.webp错误", Toast.LENGTH_SHORT).show()
null
}
}
private fun setIdPosition(position: Int) {
infoDrawerDelta = position.toFloat()
@@ -229,19 +409,24 @@ class ViewMangaActivity : TitleActivityTemplate() {
@ExperimentalStdlibApi
@SuppressLint("SetTextI18n")
private fun prepareItems(size: Int) {
ttitle.text = handler.manga?.results?.chapter?.name
prepareVP()
prepareInfoBar(size)
if (notUseVP && !isVertical) loadOneImg()
prepareIdBtVH()
toolsBox.dp2px(67)?.let { setIdPosition(it) }
prepareIdBtFullScreen()
prepareIdBtVP()
prepareIdBtLR()
handler.progressLog?.let {
//it["uuid"] = handler.manga?.results?.comic?.uuid
it["name"] = inftitle.ttitle.text
private fun prepareItems() {
try {
prepareVP()
//if (!isVertical) restorePN()
prepareInfoBar()
if (notUseVP && !isVertical && !isPnValid) loadOneImg()
prepareIdBtVH()
toolsBox.dp2px(67)?.let { setIdPosition(it) }
prepareIdBtCut()
prepareIdBtVP()
prepareIdBtLR()
/*progressLog?.let {
it["chapterId"] = hm.chapterId.toString()
it["name"] = inftitle.ttitle.text
}*/
}catch (e: Exception) {
e.printStackTrace()
toolsBox.toastError("准备控件错误")
}
}
@@ -253,6 +438,14 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
}
private fun prepareIdBtCut() {
idtbcut.isChecked = cut
idtbcut.setOnClickListener {
p["useCut"] = if (idtbcut.isChecked) "true" else "false"
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
}
}
private fun prepareIdBtLR() {
idtblr.isChecked = r2l
idtblr.setOnClickListener {
@@ -285,11 +478,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
super.onPageSelected(position)
}
})
if (r2l) vp.currentItem = count - 1
if (r2l && !isPnValid) vp.currentItem = realCount - 1
}
}
private fun updateSeekBar() {
fun updateSeekBar() {
if (!isInSeek) hideObjs()
updateSeekText()
updateSeekProgress()
@@ -297,17 +490,18 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
@SuppressLint("SetTextI18n")
private fun prepareInfoBar(size: Int) {
private fun prepareInfoBar() {
oneinfo.alpha = 0F
infseek.visibility = View.GONE
isearch.visibility = View.GONE
inftitle.ttitle.text = handler.manga?.results?.chapter?.name
inftxtprogress.text = "$pageNum/$size"
inftxtprogress.text = "$pageNum/$realCount"
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(p0: SeekBar?, p1: Int, isHuman: Boolean) {
Log.d("MyVM", "seek to ${p1 * realCount / 100}")
if (isHuman) {
if (p1 >= (pageNum + 1) * 100 / size) scrollForward()
else if (p1 < (pageNum - 1) * 100 / size) scrollBack()
if (p1 >= (pageNum + 1) * 100 / realCount) scrollForward()
else if (p1 < (pageNum - 1) * 100 / realCount) scrollBack()
}
}
override fun onStartTrackingTouch(p0: SeekBar?) {
@@ -318,6 +512,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
isInSeek = false
}
})
isearch.setImageResource(R.drawable.ic_author)
isearch.setOnClickListener {
handler.sendEmptyMessage(3)
}
@@ -330,16 +525,16 @@ class ViewMangaActivity : TitleActivityTemplate() {
val vsps = vsp as SpringView
vsps.footerView.lht.text = "更多"
vsps.headerView.lht.text = "更多"
val pm = PagesManager(WeakReference(this))
pm = PagesManager(WeakReference(this))
vsps.setListener(object :SpringView.OnFreshListener{
override fun onLoadmore() {
//scrollForward()
pm.toPage(true)
pm?.toPage(true)
vsps.onFinishFreshAndLoad()
}
override fun onRefresh() {
//scrollBack()
pm.toPage(false)
pm?.toPage(false)
vsps.onFinishFreshAndLoad()
}
})
@@ -350,8 +545,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
psivs.setOnScrollChangeListener { _, _, scrollY, _, _ ->
isInScroll = true
if(!isInSeek){
val newCurrent = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt()
pageNum += newCurrent - currentItem % verticalLoadMaxCount
val delta = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt() - currentItem % verticalLoadMaxCount
if(delta != 0 && !(delta > 0 && pageNum == size)) {
pageNum += delta
Log.d("MyVM", "Scroll to offset $delta")
}
}
}
}
@@ -361,14 +559,6 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
}
private fun prepareIdBtFullScreen() {
idtbfullscreen.isChecked = !useFullScreen
idtbfullscreen.setOnClickListener {
p["useFullScreen"] = if (idtbfullscreen.isChecked) "true" else "false"
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show()
}
}
fun scrollBack() {
isInScroll = false
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0){
@@ -384,20 +574,19 @@ class ViewMangaActivity : TitleActivityTemplate() {
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) handler.sendEmptyMessage(10)
}
@SuppressLint("SetTextI18n")
private fun updateSeekText() {
inftxtprogress.text = "$pageNum/$count"
inftxtprogress.text = "$pageNum/$realCount"
}
private fun updateSeekProgress() {
infseek.progress = pageNum * 100 / count
infseek.progress = pageNum * 100 / realCount
}
override fun onDestroy() {
dlhandler?.sendEmptyMessage(0)
tt.canDo = false
destroy = true
dlhandler = null
handler.destroy()
super.onDestroy()
@@ -415,22 +604,30 @@ class ViewMangaActivity : TitleActivityTemplate() {
@SuppressLint("ClickableViewAccessibility", "SetTextI18n")
override fun onBindViewHolder(holder: ViewData, position: Int) {
val pos = if (r2l) count - position - 1 else position
if (zipFile?.exists() == true) getImgBitmap(pos)?.let {
Glide.with(this@ViewMangaActivity).load(it)
//.thumbnail(Glide.with(this@ViewMangaActivity).load(R.drawable.load))
.into(holder.itemView.onei)
//holder.itemView.onei.setImageBitmap(it)
val pos = if (r2l) realCount - position - 1 else position
val index2load = if(cut) Math.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)
}
else getImgUrl(index2load)?.let{
if(useCut){
val thisOneI = holder.itemView.onei
Glide.with(this@ViewMangaActivity)
.asBitmap()
.load(GlideUrl(it, CMApi.myGlideHeaders)
).into(object : SimpleTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
thisOneI.setImageBitmap(cutBitmap(resource, isLeft))
} })
} else Glide.with(this@ViewMangaActivity).load(GlideUrl(it, CMApi.myGlideHeaders)).into(holder.itemView.onei)
}
else Glide.with(this@ViewMangaActivity).load(
GlideUrl(getImgUrl(pos), CMApi.myGlideHeaders))
.timeout(10000)
//.thumbnail(Glide.with(this@ViewMangaActivity).load(R.drawable.load))
.into(holder.itemView.onei)
}
override fun getItemCount(): Int {
return count
return realCount
}
}
}

View File

@@ -39,7 +39,7 @@
app:layout_constraintVertical_bias="0.0" />
<ToggleButton
android:id="@+id/idtbfullscreen"
android:id="@+id/idtbcut"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
@@ -47,8 +47,8 @@
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@drawable/toggle_button"
android:textOff="全屏开"
android:textOn="全屏关"
android:textOff="切分关闭"
android:textOn="双页切分"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/idtbvh"
app:layout_constraintStart_toStartOf="parent"
@@ -64,8 +64,8 @@
android:textOff="横向"
android:textOn="竖向"
app:layout_constraintEnd_toStartOf="@id/idtbvp"
app:layout_constraintStart_toEndOf="@+id/idtbfullscreen"
app:layout_constraintTop_toTopOf="@+id/idtbfullscreen" />
app:layout_constraintStart_toEndOf="@+id/idtbcut"
app:layout_constraintTop_toTopOf="@+id/idtbcut" />
<ToggleButton
android:id="@+id/idtbvp"
@@ -77,7 +77,7 @@
android:textOn="动画关"
app:layout_constraintEnd_toStartOf="@+id/idtblr"
app:layout_constraintStart_toEndOf="@id/idtbvh"
app:layout_constraintTop_toTopOf="@+id/idtbfullscreen" />
app:layout_constraintTop_toTopOf="@+id/idtbcut" />
<ToggleButton
android:id="@+id/idtblr"
@@ -89,7 +89,7 @@
android:textOn="←后 前→"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/idtbvp"
app:layout_constraintTop_toTopOf="@+id/idtbfullscreen" />
app:layout_constraintTop_toTopOf="@+id/idtbcut" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -134,6 +134,20 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_out_left_exit"
app:popExitAnim="@anim/slide_in_right_exit"/>
<action
android:id="@+id/action_nav_book_to_nav_author"
app:destination="@id/nav_author"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_out_left_exit"
app:popExitAnim="@anim/slide_in_right_exit"/>
<action
android:id="@+id/action_nav_book_to_nav_caption"
app:destination="@id/nav_caption"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_out_left_exit"
app:popExitAnim="@anim/slide_in_right_exit"/>
</fragment>
<fragment
@@ -189,7 +203,7 @@
android:id="@+id/nav_finish"
android:name="top.fumiama.copymanga.ui.cardflow.finish.FinishFragment"
android:label="@string/complete"
tools:layout="@layout/fragment_newest" >
tools:layout="@layout/fragment_statuscardflow" >
<action
android:id="@+id/action_nav_finish_to_nav_book"
app:destination="@id/nav_book"
@@ -199,6 +213,34 @@
app:popExitAnim="@anim/slide_in_right_exit"/>
</fragment>
<fragment
android:id="@+id/nav_author"
android:name="top.fumiama.copymanga.ui.cardflow.author.AuthorFragment"
android:label="@string/author"
tools:layout="@layout/fragment_statuscardflow" >
<action
android:id="@+id/action_nav_author_to_nav_book"
app:destination="@id/nav_book"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_out_left_exit"
app:popExitAnim="@anim/slide_in_right_exit"/>
</fragment>
<fragment
android:id="@+id/nav_caption"
android:name="top.fumiama.copymanga.ui.cardflow.caption.CaptionFragment"
android:label="@string/caption"
tools:layout="@layout/fragment_statuscardflow" >
<action
android:id="@+id/action_nav_caption_to_nav_book"
app:destination="@id/nav_book"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_out_left_exit"
app:popExitAnim="@anim/slide_in_right_exit"/>
</fragment>
<fragment
android:id="@+id/nav_group"
android:name="top.fumiama.copymanga.ui.comicdl.ComicDlFragment"

View File

@@ -44,6 +44,8 @@
<string name="recommendApiUrl">https://api.copymanga.com/api/v3/recs?pos=3200102&amp;limit=21&amp;offset=%1$d&amp;platform=3</string>
<string name="newestApiUrl">https://api.copymanga.com/api/v3/update/newest?limit=21&amp;offset=%1$d&amp;platform=3</string>
<string name="finishApiUrl">https://api.copymanga.com/api/v3/comics?limit=21&amp;offset=%1$d&amp;ordering=%2$s&amp;top=finish&amp;platform=3</string>
<string name="authorApiUrl">https://api.copymanga.com/api/v3/comics?limit=21&amp;offset=%1$d&amp;ordering=%2$s&amp;author=%3$s&amp;platform=3</string>
<string name="captionApiUrl">https://api.copymanga.com/api/v3/comics?limit=21&amp;offset=%1$d&amp;ordering=%2$s&amp;theme=%3$s&amp;platform=3</string>
<string name="complete">已完结</string>
@@ -75,4 +77,7 @@
<string name="rank_week">近七天</string>
<string name="rank_month">近三十天</string>
<string name="rank_all">总榜单</string>
<string name="author">作者</string>
<string name="caption">标签</string>
</resources>