1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-26 05:42:31 +08:00
新增
1. 自定义拷贝版本号
2. 图片加载失败时显示重新加载按钮
修复
1. APP版本过低 (fix #61)
2. 排行从详情返回后筛选无法使用
优化
1. 默认API改为api.mangacopy.com
2. 弱网络环境下图片加载
This commit is contained in:
源文雨
2024-04-02 01:41:26 +09:00
parent 9347a8d29d
commit 5ea5ad631e
18 changed files with 282 additions and 154 deletions

View File

@@ -8,8 +8,8 @@ android {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 55 versionCode 56
versionName '2.2.7' versionName '2.2.8'
resourceConfigurations += ['zh', 'zh-rCN'] resourceConfigurations += ['zh', 'zh-rCN']
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -235,6 +235,7 @@ class MainActivity : AppCompatActivity() {
if(avatar != "") if(avatar != "")
Glide.with(this@MainActivity).load(avatar) Glide.with(this@MainActivity).load(avatar)
.apply(RequestOptions.bitmapTransform(CircleCrop())) .apply(RequestOptions.bitmapTransform(CircleCrop()))
.timeout(60000)
.into(this@ic) .into(this@ic)
else setImageResource(R.mipmap.ic_launcher) else setImageResource(R.mipmap.ic_launcher)
} } } }

View File

@@ -18,7 +18,7 @@ class Book(val path: String, private val getString: (Int) -> String, private val
private val mBookApiUrl = getString(R.string.bookInfoApiUrl).format(CMApi.myHostApiUrl, path).let { private val mBookApiUrl = getString(R.string.bookInfoApiUrl).format(CMApi.myHostApiUrl, path).let {
CMApi.apiProxy?.wrap(it)?:it CMApi.apiProxy?.wrap(it)?:it
} }
private val mUserAgent = getString(R.string.pc_ua) private val mUserAgent = getString(R.string.pc_ua).format(DownloadTools.app_ver)
private var mBook: BookInfoStructure? = null private var mBook: BookInfoStructure? = null
private var mGroupPathWords = arrayOf<String>() private var mGroupPathWords = arrayOf<String>()
private var mKeys = arrayOf<String>() private var mKeys = arrayOf<String>()

View File

@@ -13,8 +13,8 @@ class Shelf(private val token: String, getString: (Int) -> String) {
private val hostUrl: String = getString(R.string.hostUrl) private val hostUrl: String = getString(R.string.hostUrl)
private val apiUrl: String = getString(R.string.shelfOperateApiUrl).format(hostUrl) private val apiUrl: String = getString(R.string.shelfOperateApiUrl).format(hostUrl)
private val queryApiUrlTemplate = getString(R.string.bookUserQueryApiUrl) private val queryApiUrlTemplate = getString(R.string.bookUserQueryApiUrl)
private val referer: String = getString(R.string.referer) private val referer: String = getString(R.string.referer).format(DownloadTools.app_ver)
private val ua: String = getString(R.string.pc_ua) private val ua: String = getString(R.string.pc_ua).format(DownloadTools.app_ver)
private val addApiUrl get() = "$apiUrl?platform=3".let { CMApi.apiProxy?.wrap(it)?:it } private val addApiUrl get() = "$apiUrl?platform=3".let { CMApi.apiProxy?.wrap(it)?:it }
private val delApiUrl get() = "${apiUrl}s?platform=3".let { CMApi.apiProxy?.wrap(it)?:it } private val delApiUrl get() = "${apiUrl}s?platform=3".let { CMApi.apiProxy?.wrap(it)?:it }
suspend fun add(comicId: String): String = withContext(Dispatchers.IO) { suspend fun add(comicId: String): String = withContext(Dispatchers.IO) {

View File

@@ -80,7 +80,7 @@ open class AutoDownloadHandler(
try { try {
val data = DownloadTools.getHttpContent( val data = DownloadTools.getHttpContent(
CMApi.apiProxy?.wrap(url)?:url, null, CMApi.apiProxy?.wrap(url)?:url, null,
mainWeakReference?.get()?.getString(R.string.pc_ua)!! DownloadTools.pc_ua
) )
if(exit) return@withContext if(exit) return@withContext
val fi = data.inputStream() val fi = data.inputStream()

View File

@@ -18,8 +18,8 @@ class PausableDownloader(private val url: String, private val waitMilliseconds:
try { try {
val data = (DownloadTools.getHttpContent( val data = (DownloadTools.getHttpContent(
(if(isApi) CMApi.apiProxy?.wrap(url) else null)?:url, (if(isApi) CMApi.apiProxy?.wrap(url) else null)?:url,
mainWeakReference?.get()?.getString(R.string.referer)!!, DownloadTools.referer,
mainWeakReference?.get()?.getString(R.string.pc_ua)!! DownloadTools.pc_ua
)) ))
whenFinish?.let { it(data) } whenFinish?.let { it(data) }
return@withContext true return@withContext true

View File

@@ -133,7 +133,7 @@ class CardList(
).addListener(GlideHideLottieViewListener(WeakReference(it.laic)) { ).addListener(GlideHideLottieViewListener(WeakReference(it.laic)) {
if (exitCardList) return@GlideHideLottieViewListener if (exitCardList) return@GlideHideLottieViewListener
cardLoadingWaits.decrementAndGet() cardLoadingWaits.decrementAndGet()
}) }).timeout(60000)
if (waitMillis > 0) it.imic.postDelayed({ if (waitMillis > 0) it.imic.postDelayed({
if (exitCardList) return@postDelayed if (exitCardList) return@postDelayed
g.into(it.imic) g.into(it.imic)

View File

@@ -3,6 +3,7 @@ package top.fumiama.copymanga.tools.api
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.bumptech.glide.load.model.LazyHeaders import com.bumptech.glide.load.model.LazyHeaders
import top.fumiama.copymanga.MainActivity 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.Proxy
import top.fumiama.copymanga.tools.http.Resolution import top.fumiama.copymanga.tools.http.Resolution
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
@@ -36,20 +37,11 @@ object CMApi {
PreferenceManager.getDefaultSharedPreferences(it).apply { PreferenceManager.getDefaultSharedPreferences(it).apply {
if (field === null) if (field === null)
field = LazyHeaders.Builder() field = LazyHeaders.Builder()
.addHeader( .addHeader("referer", DownloadTools.referer)
"referer", .addHeader("User-Agent", DownloadTools.pc_ua)
MainActivity.mainWeakReference?.get()?.getString(R.string.referer)!!
)
.addHeader(
"User-Agent",
MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)!!
)
.addHeader("source", "copyApp") .addHeader("source", "copyApp")
.addHeader("webp", "1") .addHeader("webp", "1")
.addHeader( .addHeader("version", DownloadTools.app_ver)
"version",
MainActivity.mainWeakReference?.get()?.getString(R.string.app_ver)!!
)
.addHeader( .addHeader(
"region", "region",
if (!getBoolean("settings_cat_net", false)) "1" else "0" if (!getBoolean("settings_cat_net", false)) "1" else "0"

View File

@@ -13,6 +13,13 @@ import java.util.concurrent.Callable
import java.util.concurrent.FutureTask import java.util.concurrent.FutureTask
object DownloadTools { object DownloadTools {
val app_ver = MainActivity.mainWeakReference?.get()?.let { main ->
PreferenceManager.getDefaultSharedPreferences(main)
?.getString("settings_cat_general_et_app_version", main.getString(R.string.app_ver))
?:main.getString(R.string.app_ver)
}!!
val pc_ua = MainActivity.mainWeakReference?.get()!!.getString(R.string.pc_ua).format(app_ver)
val referer = MainActivity.mainWeakReference?.get()!!.getString(R.string.referer).format(app_ver)
fun getApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null, timeout: Int = 20000) = fun getApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null, timeout: Int = 20000) =
url.let { url.let {
val connection = URL(url).openConnection() as HttpURLConnection val connection = URL(url).openConnection() as HttpURLConnection
@@ -30,7 +37,7 @@ object DownloadTools {
setRequestProperty("region", if(!getBoolean("settings_cat_net_sw_use_foreign", false)) "1" else "0") setRequestProperty("region", if(!getBoolean("settings_cat_net_sw_use_foreign", false)) "1" else "0")
} }
it.getPreferences(Context.MODE_PRIVATE).apply { it.getPreferences(Context.MODE_PRIVATE).apply {
setRequestProperty("version", it.getString(R.string.app_ver)) setRequestProperty("version", app_ver)
getString("token", "")?.let { tk -> getString("token", "")?.let { tk ->
setRequestProperty("authorization", "Token $tk") setRequestProperty("authorization", "Token $tk")
} }

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.ui.book package top.fumiama.copymanga.ui.book
import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -14,8 +15,12 @@ import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.android.synthetic.main.app_bar_main.* import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.card_book.* import kotlinx.android.synthetic.main.card_book.*
@@ -80,17 +85,36 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
private fun setCover() { private fun setCover() {
if (exit) return if (exit) return
that?.apply { that?.apply {
val load = Glide.with(this).load( Glide.with(this).load(
if (book?.cover != null) if (book?.cover != null)
GlideUrl(CMApi.imageProxy?.wrap(book?.cover!!)?:book?.cover!!, CMApi.myGlideHeaders) GlideUrl(CMApi.imageProxy?.wrap(book?.cover!!)?:book?.cover!!, CMApi.myGlideHeaders)
else book?.cachedCover else book?.cachedCover
).addListener(GlideHideLottieViewListener(WeakReference(laic))) )
load.into(imic) .timeout(60000)
context?.let { it1 -> GlideBlurTransformation(it1) } .addListener(GlideHideLottieViewListener(WeakReference(laic)))
?.let { it2 -> RequestOptions.bitmapTransform(it2) } .addListener(object : RequestListener<Drawable> {
?.let { it3 -> load.apply(it3).into(lbibg) } override fun onLoadFailed(
//imf?.visibility = View.GONE e: GlideException?,
//fbl?.addView(divider) model: Any?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
context?.let { it1 -> GlideBlurTransformation(it1) }
?.let { it2 -> RequestOptions.bitmapTransform(it2) }
?.let { it3 -> Glide.with(this@apply).load(resource).apply(it3).into(lbibg) }
return false
}
}).into(imic)
} }
} }

View File

@@ -4,8 +4,6 @@ import android.os.Bundle
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kotlinx.android.synthetic.main.fragment_rank.* import kotlinx.android.synthetic.main.fragment_rank.*
import kotlinx.android.synthetic.main.line_rank.view.* import kotlinx.android.synthetic.main.line_rank.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import top.fumiama.copymanga.template.ui.InfoCardLoader import top.fumiama.copymanga.template.ui.InfoCardLoader
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
@@ -27,12 +25,14 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
wr = null
ad?.exit = true ad?.exit = true
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
ad?.exit = true wr = WeakReference(this)
ad?.exit = false
} }
override fun onDestroy() { override fun onDestroy() {
@@ -72,7 +72,7 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank
} }
fun showSexInfo(toolsBox: UITools) { fun showSexInfo(toolsBox: UITools) {
if (ad?.exit != false) return if (ad?.exit == true) return
toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型", toolsBox.buildInfo("切换类型", "选择一种想筛选的漫画类型",
"男频", "全部", "女频", { "男频", "全部", "女频", {
if(!isLoading) { if(!isLoading) {

View File

@@ -205,7 +205,9 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
//Log.d("MyHomeFVP", "Load img: $it") //Log.d("MyHomeFVP", "Load img: $it")
Glide.with(this@HomeFragment).load( Glide.with(this@HomeFragment).load(
GlideUrl(CMApi.imageProxy?.wrap(it)?:it, CMApi.myGlideHeaders) GlideUrl(CMApi.imageProxy?.wrap(it)?:it, CMApi.myGlideHeaders)
).addListener(GlideHideLottieViewListener(WeakReference(holder.itemView.lai))).into(holder.itemView.vpi) )
.addListener(GlideHideLottieViewListener(WeakReference(holder.itemView.lai)))
.timeout(60000).into(holder.itemView.vpi)
} }
holder.itemView.vpt.text = thisBanner?.brief holder.itemView.vpt.text = thisBanner?.brief
holder.itemView.vpc.setOnClickListener { holder.itemView.vpc.setOnClickListener {
@@ -244,6 +246,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
context?.let { context?.let {
Glide.with(it).load(R.drawable.img_defmask) Glide.with(it).load(R.drawable.img_defmask)
.addListener(GlideHideLottieViewListener(WeakReference(laic))) .addListener(GlideHideLottieViewListener(WeakReference(laic)))
.timeout(60000)
.into(imic) .into(imic)
} }
cic.isClickable = false cic.isClickable = false
@@ -275,7 +278,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
Glide.with(it) Glide.with(it)
.load(GlideUrl(CMApi.imageProxy?.wrap(cover)?:cover, CMApi.myGlideHeaders)) .load(GlideUrl(CMApi.imageProxy?.wrap(cover)?:cover, CMApi.myGlideHeaders))
.addListener(GlideHideLottieViewListener(WeakReference(laic))) .addListener(GlideHideLottieViewListener(WeakReference(laic)))
.into(imic) .timeout(60000).into(imic)
} }
lwc.setOnClickListener { lwc.setOnClickListener {
val bundle = Bundle() val bundle = Bundle()

View File

@@ -341,7 +341,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
val g = Glide.with(it).load(GlideUrl(CMApi.imageProxy?.wrap(img)?:img, CMApi.myGlideHeaders)) val g = Glide.with(it).load(GlideUrl(CMApi.imageProxy?.wrap(img)?:img, CMApi.myGlideHeaders))
.addListener(GlideHideLottieViewListener(WeakReference(cv.laic)) { .addListener(GlideHideLottieViewListener(WeakReference(cv.laic)) {
cardLoadingWaits.decrementAndGet() cardLoadingWaits.decrementAndGet()
}) }).timeout(60000)
if (waitMillis > 0) cv.imic.postDelayed({ if (waitMillis > 0) cv.imic.postDelayed({
g.into(cv.imic) g.into(cv.imic)
}, waitMillis) else cv.imic.post { g.into(cv.imic) } }, waitMillis) else cv.imic.post { g.into(cv.imic) }

View File

@@ -70,7 +70,7 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
} else { } else {
showInfCard(); true showInfCard(); true
} }
LOAD_IMG_ON -> { /*LOAD_IMG_ON -> {
val scaleImageView = msg.obj as ScaleImageView val scaleImageView = msg.obj as ScaleImageView
// msg.arg2: isLast // msg.arg2: isLast
wv.get()?.apply { wv.get()?.apply {
@@ -80,10 +80,9 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
} }
//scaleImageView.setHeight2FitImgWidth() //scaleImageView.setHeight2FitImgWidth()
//if(msg.arg2 == 1) sendEmptyMessage(DELAYED_RESTORE_PAGE_NUMBER) //if(msg.arg2 == 1) sendEmptyMessage(DELAYED_RESTORE_PAGE_NUMBER)
} }*/
CLEAR_IMG_ON -> { CLEAR_IMG_ON -> {
val img = msg.obj as ScaleImageView (msg.obj as ScaleImageView).apply { post { visibility = View.GONE } }
img.visibility = View.GONE
//sendEmptyMessage(DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO) //sendEmptyMessage(DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO)
} }
PREPARE_LAST_PAGE -> wv.get()?.prepareLastPage(msg.arg1, msg.arg2) PREPARE_LAST_PAGE -> wv.get()?.prepareLastPage(msg.arg1, msg.arg2)
@@ -207,7 +206,7 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
vprog?.visibility = View.GONE vprog?.visibility = View.GONE
} }
} }
private suspend fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = withContext(Dispatchers.IO) { private suspend fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) {
val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20) val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)
Log.d("MyVMH", "Fun: loadImagesIntoLine($item, $maxCount)") Log.d("MyVMH", "Fun: loadImagesIntoLine($item, $maxCount)")
wv.get()?.realCount?.let { count -> wv.get()?.realCount?.let { count ->
@@ -216,8 +215,15 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
val loadCount = (if(notFull) count - item else maxCount) - 1 val loadCount = (if(notFull) count - item else maxCount) - 1
obtainMessage(INIT_IMAGE_COUNT, loadCount+1, 0).sendToTarget() obtainMessage(INIT_IMAGE_COUNT, loadCount+1, 0).sendToTarget()
Log.d("MyVMH", "count: $count, loadCount: $loadCount, notFull: $notFull") Log.d("MyVMH", "count: $count, loadCount: $loadCount, notFull: $notFull")
if(loadCount >= 0) for(i in 0..loadCount) { if(loadCount >= 0) withContext(Dispatchers.IO) {
obtainMessage(LOAD_IMG_ON,item + i, if(i == loadCount - 1) 1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget() for(i in 0..loadCount) {
wv.get()?.apply {
val p = item + i
scrollPositions[i] = p
launch { loadImgOn(scrollImages[i], scrollButtons[i], p, false) }
}
//obtainMessage(LOAD_IMG_ON,item + i, if(i == loadCount - 1) 1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget()
}
} }
//else sendEmptyMessageDelayed(RESTORE_PAGE_NUMBER, 233) //else sendEmptyMessageDelayed(RESTORE_PAGE_NUMBER, 233)
if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget() if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget()
@@ -267,7 +273,7 @@ class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, pri
const val HIDE_INFO_CARD = 1 const val HIDE_INFO_CARD = 1
const val SHOW_INFO_CARD = 2 const val SHOW_INFO_CARD = 2
const val TRIGGER_INFO_CARD = 3 const val TRIGGER_INFO_CARD = 3
const val LOAD_IMG_ON = 4 //const val LOAD_IMG_ON = 4
const val CLEAR_IMG_ON = 5 const val CLEAR_IMG_ON = 5
const val PREPARE_LAST_PAGE = 6 const val PREPARE_LAST_PAGE = 6
const val DIALOG_SHOW = 7 const val DIALOG_SHOW = 7

View File

@@ -20,6 +20,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets import android.view.WindowInsets
import android.view.WindowInsetsController import android.view.WindowInsetsController
import android.widget.Button
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
@@ -31,8 +32,12 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
import com.liaoinstan.springview.widget.SpringView import com.liaoinstan.springview.widget.SpringView
import kotlinx.android.synthetic.main.activity_viewmanga.* import kotlinx.android.synthetic.main.activity_viewmanga.*
@@ -45,6 +50,7 @@ import kotlinx.android.synthetic.main.widget_titlebar.*
import kotlinx.android.synthetic.main.widget_titlebar.view.* import kotlinx.android.synthetic.main.widget_titlebar.view.*
import kotlinx.android.synthetic.main.widget_viewmangainfo.* import kotlinx.android.synthetic.main.widget_viewmangainfo.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
@@ -68,13 +74,15 @@ import kotlin.math.abs
class ViewMangaActivity : TitleActivityTemplate() { class ViewMangaActivity : TitleActivityTemplate() {
var count = 0 var count = 0
private lateinit var handler: VMHandler private lateinit var mHandler: VMHandler
lateinit var tt: TimeThread lateinit var tt: TimeThread
var clicked = 0 var clicked = 0
private var isInSeek = false private var isInSeek = false
private var isInScroll = true private var isInScroll = true
//private var progressLog: PropertiesTools? = null //private var progressLog: PropertiesTools? = null
var scrollImages = arrayOf<ScaleImageView>() var scrollImages = arrayOf<ScaleImageView>()
var scrollButtons = arrayOf<Button>()
var scrollPositions = arrayOf<Int>()
//var zipFirst = false //var zipFirst = false
//private var useFullScreen = false //private var useFullScreen = false
var r2l = true var r2l = true
@@ -169,11 +177,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
isVertical = pb["vertical"] isVertical = pb["vertical"]
notUseVP = pb["noVP"] || isVertical notUseVP = pb["noVP"] || isVertical
//url = intent.getStringExtra("url") //url = intent.getStringExtra("url")
handler = VMHandler(this@ViewMangaActivity, if(urlArray.isNotEmpty()) urlArray[position] else "", resources.getStringArray(R.array.weeks)) mHandler = VMHandler(this@ViewMangaActivity, if(urlArray.isNotEmpty()) urlArray[position] else "", resources.getStringArray(R.array.weeks))
lifecycleScope.launch { lifecycleScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
settingsPref?.getInt("settings_cat_vm_sb_quality", 100)?.let { q = if (it > 0) it else 100 } 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 = TimeThread(mHandler, VMHandler.SET_NET_INFO, 10000)
tt.canDo = true tt.canDo = true
tt.start() tt.start()
volTurnPage = settingsPref?.getBoolean("settings_cat_vm_sw_vol_turn", false)?:false volTurnPage = settingsPref?.getBoolean("settings_cat_vm_sw_vol_turn", false)?:false
@@ -184,7 +192,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
Log.d("MyVM", "Now ZipFile is $zipFile") Log.d("MyVM", "Now ZipFile is $zipFile")
try { try {
if (zipFile != null && zipFile?.exists() == true) { if (zipFile != null && zipFile?.exists() == true) {
if (!handler.loadFromFile(zipFile!!)) prepareImgFromWeb() if (!mHandler.loadFromFile(zipFile!!)) prepareImgFromWeb()
} else prepareImgFromWeb() } else prepareImgFromWeb()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
@@ -231,7 +239,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
private suspend fun alertCellar() = withContext(Dispatchers.Main) { private suspend fun alertCellar() = withContext(Dispatchers.Main) {
toolsBox.buildInfo( toolsBox.buildInfo(
"注意", "要使用使用流量观看吗?", "确定", "本次阅读不再提醒", "取消", "注意", "要使用使用流量观看吗?", "确定", "本次阅读不再提醒", "取消",
{ handler.startLoad() }, { noCellarAlert = true; handler.startLoad() }, { finish() } { mHandler.startLoad() }, { noCellarAlert = true; mHandler.startLoad() }, { finish() }
) )
} }
@@ -260,10 +268,10 @@ class ViewMangaActivity : TitleActivityTemplate() {
getImgUrlArray()?.apply { getImgUrlArray()?.apply {
if(cut) { if(cut) {
Log.d("MyVM", "is cut, load all pages...") Log.d("MyVM", "is cut, load all pages...")
handler.sendEmptyMessage(VMHandler.DIALOG_SHOW) // showDl mHandler.sendEmptyMessage(VMHandler.DIALOG_SHOW) // showDl
isCut = BooleanArray(size) isCut = BooleanArray(size)
forEachIndexed { i, it -> forEachIndexed { i, it ->
handler.obtainMessage(VMHandler.SET_DL_TEXT, "$i/$size").sendToTarget() mHandler.obtainMessage(VMHandler.SET_DL_TEXT, "$i/$size").sendToTarget()
if(it != null) try { if(it != null) try {
DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let { DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), 1024)?.inputStream()?.let {
isCut[i] = canCut(it) isCut[i] = canCut(it)
@@ -290,7 +298,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
indexMap += index+1 indexMap += index+1
if(b) indexMap += -(index+1) if(b) indexMap += -(index+1)
} }
handler.sendEmptyMessage(15) // hideDl mHandler.sendEmptyMessage(15) // hideDl
Log.d("MyVM", "load all pages finished") Log.d("MyVM", "load all pages finished")
} }
count = size count = size
@@ -301,7 +309,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
suspend fun initManga() = withContext(Dispatchers.IO) { suspend fun initManga() = withContext(Dispatchers.IO) {
val uuid = handler.manga?.results?.chapter?.uuid val uuid = mHandler.manga?.results?.chapter?.uuid
Log.d("MyVM", "initManga, chapter uuid: $uuid") Log.d("MyVM", "initManga, chapter uuid: $uuid")
if (uuid != null && uuid != "") { if (uuid != null && uuid != "") {
pn = getPreferences(MODE_PRIVATE).getInt(uuid, -4) pn = getPreferences(MODE_PRIVATE).getInt(uuid, -4)
@@ -316,7 +324,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
private suspend fun prepareImgFromWeb() { private suspend fun prepareImgFromWeb() {
if(!noCellarAlert && toolsBox.netInfo == getString(R.string.TRANSPORT_CELLULAR)) alertCellar() if(!noCellarAlert && toolsBox.netInfo == getString(R.string.TRANSPORT_CELLULAR)) alertCellar()
else handler.startLoad() else mHandler.startLoad()
} }
private fun canCut(inputStream: InputStream): Boolean{ private fun canCut(inputStream: InputStream): Boolean{
@@ -353,7 +361,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
else (if (notUseVP) currentItem else vp.currentItem) + 1 else (if (notUseVP) currentItem else vp.currentItem) + 1
} }
private fun setPageNumber(num: Int) { private fun setPageNumber(num: Int) { lifecycleScope.launch {
Log.d("MyVM", "setPageNumber($num)") Log.d("MyVM", "setPageNumber($num)")
if (r2l && !notUseVP) vp.currentItem = realCount - num if (r2l && !notUseVP) vp.currentItem = realCount - num
else if (notUseVP) { else if (notUseVP) {
@@ -362,53 +370,36 @@ class ViewMangaActivity : TitleActivityTemplate() {
val offset = currentItem % verticalLoadMaxCount val offset = currentItem % verticalLoadMaxCount
Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}") Log.d("MyVM", "Current: $currentItem, Height: ${psivl.height}, scrollY: ${psivs.scrollY}")
if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size if (!isInScroll || isInSeek) psivs.scrollY = psivl.height * offset / size
lifecycleScope.launch { updateSeekBar() } updateSeekBar()
} else { } else {
currentItem = num - 1 currentItem = num - 1
try { try {
loadOneImg() loadOneImg()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
lifecycleScope.launch { withContext(Dispatchers.Main) {
toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem)) toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem))
} }
} }
} }
} else { } else {
Log.d("MyVM", "Set vp current: ${num-1}") Log.d("MyVM", "Set vp current: ${num-1}")
//var delta = num - 1 - vp.currentItem
vp.currentItem = num - 1 vp.currentItem = num - 1
/*lifecycleScope.launch {
withContext(Dispatchers.IO) {
if(delta >= 1) while (delta-- > 0){
delay(20)
withContext(Dispatchers.Main) {
vp.currentItem++
}
}
else if(delta <= -1) while (delta++ < 0){
delay(20)
withContext(Dispatchers.Main) {
vp.currentItem--
}
}
}
}*/
} }
} } }
/*fun clearImgOn(imgView: ScaleImageView){ /*fun clearImgOn(imgView: ScaleImageView){
imgView.visibility = View.GONE imgView.visibility = View.GONE
handler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO) mHandler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO)
}*/ }*/
//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 { private fun getImgUrl(position: Int) = mHandler.manga?.results?.chapter?.let {
it.contents[it.words.indexOf(position)].url it.contents[it.words.indexOf(position)].url
} }
private fun getImgUrlArray() = handler.manga?.results?.chapter?.let{ private fun getImgUrlArray() = mHandler.manga?.results?.chapter?.let{
val re = arrayOfNulls<String>(it.contents.size) val re = arrayOfNulls<String>(it.contents.size)
for(i in it.contents.indices) { for(i in it.contents.indices) {
re[i] = getImgUrl(i) re[i] = getImgUrl(i)
@@ -420,20 +411,25 @@ class ViewMangaActivity : TitleActivityTemplate() {
private suspend fun loadImg(imgView: ScaleImageView, bitmap: Bitmap, useCut: Boolean, isLeft: Boolean, isPlaceholder: Boolean = true) = withContext(Dispatchers.IO) { 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 val bitmap2load = if(!isPlaceholder && useCut) cutBitmap(bitmap, isLeft) else bitmap
withContext(Dispatchers.Main) { imgView.apply { post {
imgView.setImageBitmap(bitmap2load) setImageBitmap(bitmap2load)
if(!isPlaceholder && isVertical) { if(!isPlaceholder && isVertical) {
imgView.setHeight2FitImgWidth() setHeight2FitImgWidth()
handler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO) Log.d("MyVM", "dec remainingImageCount")
mHandler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO)
} }
} } }
} }
private suspend fun loadImgUrlInto(imgView: ScaleImageView, url: String, useCut: Boolean, isLeft: Boolean){ private suspend fun loadImgUrlInto(imgView: ScaleImageView, button: Button, url: String, useCut: Boolean, isLeft: Boolean, check: (() -> Boolean)? = null): Boolean {
Log.d("MyVM", "Load from adt: $url") Log.d("MyVM", "Load from adt: $url")
PausableDownloader(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(url)?:url), 1000, false) { val success = PausableDownloader(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(url)?:url), 1000, false) { data ->
it.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) } check?.let { it() }?.let { if(it) loadImg(imgView, BitmapFactory.decodeByteArray(data, 0, data.size), useCut, isLeft, false) }
}.run() }.run()
if (!success) button.apply { post {
visibility = View.VISIBLE
} }
return success
} }
private fun getLoadingBitmap(position: Int): Bitmap { private fun getLoadingBitmap(position: Int): Bitmap {
@@ -450,44 +446,53 @@ class ViewMangaActivity : TitleActivityTemplate() {
return loading return loading
} }
suspend fun loadImgOn(imgView: ScaleImageView, position: Int) = withContext(Dispatchers.IO) { suspend fun loadImgOn(imgView: ScaleImageView, reloadButton: Button, position: Int, isSingle: Boolean = false): Boolean = withContext(Dispatchers.IO) {
Log.d("MyVM", "Load img: $position") Log.d("MyVM", "Load img: $position")
if (position < 0 || position > realCount) return@withContext if (isSingle && position != currentItem) return@withContext true
if (position < 0 || position > realCount) return@withContext false
val index2load = if(cut) abs(indexMap[position]) -1 else position val index2load = if(cut) abs(indexMap[position]) -1 else position
val useCut = cut && isCut[index2load] val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[position] > 0 val isLeft = cut && indexMap[position] > 0
if (zipFile?.exists() == true) getImgBitmap(index2load)?.let { val success: Boolean = if (zipFile?.exists() == true) getImgBitmap(index2load)?.let {
loadImg(imgView, it, useCut, isLeft, false) loadImg(imgView, it, useCut, isLeft, false)
} true
}?:false
else { else {
val sleepTime = loadImgOnWait.getAndIncrement().toLong()*200 val sleepTime = loadImgOnWait.getAndIncrement().toLong()*200
Log.d("MyVM", "loadImgOn sleep: $sleepTime ms") Log.d("MyVM", "loadImgOn sleep: $sleepTime ms")
val re = tasks?.get(index2load) val re = tasks?.get(index2load)
if (sleepTime > 0 && re?.isDone != true) { if (sleepTime > 0 && re?.isDone != true) {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true) loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
Thread.sleep(sleepTime) delay(sleepTime)
if (isSingle && position != currentItem) return@withContext true
} }
if (re != null) { val s: Boolean = if (re != null) {
if(!re.isDone) { if(!re.isDone) {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true) loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
re.run() re.run()
} }
val data = re.get() val data = re.get()
if (isSingle && position != currentItem) return@withContext true
if(data != null && data.isNotEmpty()) { if(data != null && data.isNotEmpty()) {
BitmapFactory.decodeByteArray(data, 0, data.size)?.let { BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
loadImg(imgView, it, useCut, isLeft, false) loadImg(imgView, it, useCut, isLeft, false)
Log.d("MyVM", "Load position $position from task") Log.d("MyVM", "Load position $position from task")
}?:Log.d("MyVM", "null bitmap at $position") }?:Log.d("MyVM", "null bitmap at $position")
true
} }
else getImgUrl(index2load)?.let { else getImgUrl(index2load)?.let {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true) loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
loadImgUrlInto(imgView, it, useCut, isLeft) loadImgUrlInto(imgView, reloadButton, it, useCut, isLeft) {
} return@loadImgUrlInto !(isSingle && position != currentItem)
}
}?:false
} }
else getImgUrl(index2load)?.let { else getImgUrl(index2load)?.let {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true) loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
loadImgUrlInto(imgView, it, useCut, isLeft) loadImgUrlInto(imgView, reloadButton, it, useCut, isLeft) {
} return@loadImgUrlInto !(isSingle && position != currentItem)
}
}?:false
loadImgOnWait.decrementAndGet() loadImgOnWait.decrementAndGet()
tasks?.apply { tasks?.apply {
if (index2load >= size) return@apply if (index2load >= size) return@apply
@@ -513,34 +518,61 @@ class ViewMangaActivity : TitleActivityTemplate() {
get(pos)?.apply { get(pos)?.apply {
if(!isDone) { if(!isDone) {
tasksRunStatus?.set(pos, true) tasksRunStatus?.set(pos, true)
run() Thread(this).start()
} }
} }
} }
s
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if(imgView.visibility != View.VISIBLE) imgView.visibility = View.VISIBLE if(imgView.visibility != View.VISIBLE) imgView.visibility = View.VISIBLE
} }
return@withContext success
} }
private fun loadOneImg() { private suspend fun loadOneImg() {
lifecycleScope.launch { val img = onei
loadImgOn(onei, currentItem) oneb.apply { post {
updateSeekBar() if (!hasOnClickListeners()) setOnClickListener {
} lifecycleScope.launch {
if (loadImgOn(img, this@apply, currentItem, true)) {
post { visibility = View.GONE }
}
}
}
} }
loadImgOn(onei, oneb, currentItem, true)
updateSeekBar()
} }
private fun initImgList(){ private fun initImgList() {
for (i in 0 until verticalLoadMaxCount) { for (i in 0 until verticalLoadMaxCount) {
val newImg = ScaleImageView(this) val newOneImage = layoutInflater.inflate(R.layout.page_imgview, psivl, false)
scrollImages += newImg val img = newOneImage.onei
psivl.addView(newImg) val b = newOneImage.oneb
val p = scrollPositions.size
b.apply { post {
setOnClickListener {
lifecycleScope.launch {
if (loadImgOn(img, this@apply, scrollPositions[p])) {
post { visibility = View.GONE }
}
}
}
} }
scrollImages += img
scrollButtons += b
scrollPositions += -1
psivl.addView(newOneImage)
} }
} }
fun prepareLastPage(loadCount: Int, maxCount: Int){ fun prepareLastPage(loadCount: Int, maxCount: Int){
for (i in loadCount until maxCount) handler.obtainMessage(VMHandler.CLEAR_IMG_ON, scrollImages[i]).sendToTarget() for (i in loadCount until maxCount) {
// handler.dl?.hide() mHandler.obtainMessage(VMHandler.CLEAR_IMG_ON, scrollImages[i]).sendToTarget()
scrollButtons[i].apply { post { visibility = View.GONE } }
}
// mHandler.dl?.hide()
} }
private suspend fun getImgBitmap(position: Int): Bitmap? = withContext(Dispatchers.IO) { private suspend fun getImgBitmap(position: Int): Bitmap? = withContext(Dispatchers.IO) {
@@ -584,7 +616,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
infoDrawerDelta = position.toFloat() infoDrawerDelta = position.toFloat()
infcard.translationY = infoDrawerDelta infcard.translationY = infoDrawerDelta
Log.d("MyVM", "Set info drawer delta to $infoDrawerDelta") Log.d("MyVM", "Set info drawer delta to $infoDrawerDelta")
handler.sendEmptyMessage(if (fullyHideInfo) 16 else VMHandler.HIDE_INFO_CARD) mHandler.sendEmptyMessage(if (fullyHideInfo) 16 else VMHandler.HIDE_INFO_CARD)
} }
@ExperimentalStdlibApi @ExperimentalStdlibApi
@@ -605,15 +637,13 @@ class ViewMangaActivity : TitleActivityTemplate() {
}*/ }*/
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
lifecycleScope.launch { toolsBox.toastError(R.string.load_chapter_error)
toolsBox.toastError(R.string.load_chapter_error) finish()
finish()
}
} }
} }
private suspend fun setProgress() = withContext(Dispatchers.IO) { private suspend fun setProgress() = withContext(Dispatchers.IO) {
handler.manga?.results?.chapter?.uuid?.let { mHandler.manga?.results?.chapter?.uuid?.let {
getPreferences(MODE_PRIVATE).edit { getPreferences(MODE_PRIVATE).edit {
//it["chapterId"] = hm.chapterId.toString() //it["chapterId"] = hm.chapterId.toString()
putInt(it, pageNum) putInt(it, pageNum)
@@ -623,15 +653,21 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
} }
private fun fadeRecreate() {
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000)
oa.doOnEnd {
onecons?.removeAllViews()
psivl?.removeAllViews()
recreate()
}
oa.start()
}
private fun prepareIdBtCut() { private fun prepareIdBtCut() {
idtbcut.isChecked = cut idtbcut.isChecked = cut
idtbcut.setOnClickListener { idtbcut.setOnClickListener {
pb["useCut"] = idtbcut.isChecked pb["useCut"] = idtbcut.isChecked
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000) fadeRecreate()
oa.doOnEnd {
recreate()
}
oa.start()
} }
} }
@@ -643,11 +679,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
return@setOnClickListener return@setOnClickListener
} }
pb["r2l"] = idtblr.isChecked pb["r2l"] = idtblr.isChecked
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000) fadeRecreate()
oa.doOnEnd {
recreate()
}
oa.start()
} }
} }
@@ -659,11 +691,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
return@setOnClickListener return@setOnClickListener
} }
pb["noVP"] = idtbvp.isChecked pb["noVP"] = idtbvp.isChecked
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000) fadeRecreate()
oa.doOnEnd {
recreate()
}
oa.start()
} }
} }
@@ -701,7 +729,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
oneinfo.alpha = 0F oneinfo.alpha = 0F
infseek.visibility = View.GONE infseek.visibility = View.GONE
isearch.visibility = View.GONE isearch.visibility = View.GONE
inftitle.ttitle.text = "$comicName ${handler.manga?.results?.chapter?.name}" inftitle.ttitle.text = "$comicName ${mHandler.manga?.results?.chapter?.name}"
inftxtprogress.text = "$pageNum/$realCount" inftxtprogress.text = "$pageNum/$realCount"
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
var p = 0 var p = 0
@@ -734,7 +762,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
val pS = p val pS = p
Log.d("MyVM", "stop seek at $pS") Log.d("MyVM", "stop seek at $pS")
if (isVertical && startP/verticalLoadMaxCount != p/verticalLoadMaxCount) { if (isVertical && startP/verticalLoadMaxCount != p/verticalLoadMaxCount) {
handler.obtainMessage( mHandler.obtainMessage(
VMHandler.LOAD_ITEM_SCROLL_MODE, VMHandler.LOAD_ITEM_SCROLL_MODE,
p / verticalLoadMaxCount * verticalLoadMaxCount, p / verticalLoadMaxCount * verticalLoadMaxCount,
0, 0,
@@ -755,7 +783,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
}) })
isearch.setImageResource(R.drawable.ic_author) isearch.setImageResource(R.drawable.ic_author)
isearch.setOnClickListener { isearch.setOnClickListener {
handler.sendEmptyMessage(if (fullyHideInfo) VMHandler.TRIGGER_INFO_CARD_FULL else VMHandler.TRIGGER_INFO_CARD) // trigger info card mHandler.sendEmptyMessage(if (fullyHideInfo) VMHandler.TRIGGER_INFO_CARD_FULL else VMHandler.TRIGGER_INFO_CARD) // trigger info card
} }
} }
@@ -783,25 +811,26 @@ class ViewMangaActivity : TitleActivityTemplate() {
vp.visibility = View.GONE vp.visibility = View.GONE
vsp.visibility = View.VISIBLE vsp.visibility = View.VISIBLE
initImgList() initImgList()
handler.sendEmptyMessage(if(isPnValid) VMHandler.LOAD_PAGE_FROM_ITEM else VMHandler.LOAD_SCROLL_MODE) mHandler.sendEmptyMessage(if(isPnValid) VMHandler.LOAD_PAGE_FROM_ITEM else VMHandler.LOAD_SCROLL_MODE)
psivs.setOnScrollChangeListener { _, _, scrollY, _, _ -> psivs.setOnScrollChangeListener { _, _, scrollY, _, _ ->
isInScroll = true isInScroll = true
if(!isInSeek) { if(!isInSeek) {
val delta = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt() - currentItem % verticalLoadMaxCount val delta = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt() - currentItem % verticalLoadMaxCount
if(delta != 0 && !(delta > 0 && pageNum == size)) { if(delta != 0 && !(delta > 0 && pageNum == size)) {
pageNum += delta val fin = pageNum + delta
Log.d("MyVM", "Scroll to offset $delta") pageNum = when {
fin <= 0 -> 1
fin%verticalLoadMaxCount == 0 -> fin/verticalLoadMaxCount*verticalLoadMaxCount
else -> fin
}
Log.d("MyVM", "Scroll to offset $delta, page $pageNum")
} }
} }
} }
} }
idtbvh.setOnClickListener { idtbvh.setOnClickListener {
pb["vertical"] = idtbvh.isChecked pb["vertical"] = idtbvh.isChecked
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000) fadeRecreate()
oa.doOnEnd {
recreate()
}
oa.start()
} }
} }
@@ -813,7 +842,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
(pageNum-1).let { lifecycleScope.launch { updateSeekBar(it) } } (pageNum-1).let { lifecycleScope.launch { updateSeekBar(it) } }
return return
} }
handler.obtainMessage( mHandler.obtainMessage(
VMHandler.LOAD_ITEM_SCROLL_MODE, VMHandler.LOAD_ITEM_SCROLL_MODE,
currentItem - verticalLoadMaxCount, 0, currentItem - verticalLoadMaxCount, 0,
Runnable{ Runnable{
@@ -832,7 +861,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
(pageNum+1).let { lifecycleScope.launch { updateSeekBar(it) } } (pageNum+1).let { lifecycleScope.launch { updateSeekBar(it) } }
return return
} }
handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE) mHandler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE)
} }
} }
@@ -850,8 +879,8 @@ class ViewMangaActivity : TitleActivityTemplate() {
tt.canDo = false tt.canDo = false
destroy = true destroy = true
dlHandler = null dlHandler = null
handler.dl.dismiss() mHandler.dl.dismiss()
handler.destroy() mHandler.destroy()
super.onDestroy() super.onDestroy()
} }
@@ -875,15 +904,19 @@ class ViewMangaActivity : TitleActivityTemplate() {
getImgBitmap(index2load)?.let { getImgBitmap(index2load)?.let {
//Glide.with(this@ViewMangaActivity).load(if(useCut) cutBitmap(it, isLeft) else it).into(holder.itemView.onei) //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) holder.itemView.onei.setImageBitmap(if(useCut) cutBitmap(it, isLeft) else it)
holder.itemView.oneb.visibility = View.GONE
} }
} }
else getImgUrl(index2load)?.let{ else getImgUrl(index2load)?.let{
if(useCut){ if(useCut) {
val thisOneI = holder.itemView.onei val thisOneI = holder.itemView.onei
val thisOneB = holder.itemView.oneb
Glide.with(this@ViewMangaActivity.applicationContext) Glide.with(this@ViewMangaActivity.applicationContext)
.asBitmap() .asBitmap()
.load(GlideUrl(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), CMApi.myGlideHeaders)) .load(GlideUrl(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), CMApi.myGlideHeaders))
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.timeout(60000)
.addListener(OneButtonRequestListener(thisOneB))
.into(object : CustomTarget<Bitmap>() { .into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
thisOneI.setImageBitmap(cutBitmap(resource, isLeft)) thisOneI.setImageBitmap(cutBitmap(resource, isLeft))
@@ -892,7 +925,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
}) })
} else Glide.with(this@ViewMangaActivity.applicationContext) } else Glide.with(this@ViewMangaActivity.applicationContext)
.load(GlideUrl(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), CMApi.myGlideHeaders)) .load(GlideUrl(CMApi.resolution.wrap(CMApi.imageProxy?.wrap(it)?:it), CMApi.myGlideHeaders))
.timeout(60000)
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.addListener(OneButtonRequestListener(holder.itemView.oneb))
.into(holder.itemView.onei) .into(holder.itemView.onei)
} }
} }
@@ -900,6 +935,38 @@ class ViewMangaActivity : TitleActivityTemplate() {
override fun getItemCount(): Int { override fun getItemCount(): Int {
return realCount return realCount
} }
private inner class OneButtonRequestListener<T>(private val thisOneB: Button) : RequestListener<T> {
var mTarget: Target<T>? = null
init {
thisOneB.apply { post {
setOnClickListener { mTarget?.request?.apply {
clear()
begin()
} }
} }
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<T>,
isFirstResource: Boolean
): Boolean {
thisOneB.visibility = View.VISIBLE
mTarget = target
return false
}
override fun onResourceReady(
resource: T & Any,
model: Any,
target: Target<T>?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
thisOneB.visibility = View.GONE
return false
}
}
} }
} }
@@ -937,7 +1004,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
isearch.invalidate() isearch.invalidate()
clicked = 0 // false clicked = 0 // false
}, 300) }, 300)
handler.sendEmptyMessage(if (fullyHideInfo) VMHandler.HIDE_INFO_CARD_FULL else VMHandler.HIDE_INFO_CARD) mHandler.sendEmptyMessage(if (fullyHideInfo) VMHandler.HIDE_INFO_CARD_FULL else VMHandler.HIDE_INFO_CARD)
} }
companion object { companion object {

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/onecons" android:id="@+id/onecons"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@@ -9,4 +11,17 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<Button
android:id="@+id/oneb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_reload"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.64"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [ <!DOCTYPE resources [
<!ENTITY hosturl "api.copymanga.tv"> <!ENTITY hosturl "api.mangacopy.com">
<!ENTITY appver "2.1.7">
]> ]>
<resources> <resources>
<string name="app_name">拷贝漫画</string> <string name="app_name">拷贝漫画</string>
@@ -98,9 +99,9 @@
<string name="TRANSPORT_NULL">无网络</string> <string name="TRANSPORT_NULL">无网络</string>
<string name="TRANSPORT_ERROR">网络错误</string> <string name="TRANSPORT_ERROR">网络错误</string>
<string name="pc_ua">COPY/2.0.7</string> <string name="pc_ua">COPY/%1$s</string>
<string name="app_ver">2.0.7</string> <string name="app_ver">&appver;</string>
<string name="referer">com.copymanga.app-2.0.7</string> <string name="referer">com.copymanga.app-%1$s</string>
<string name="menu_update_time">更新时间</string> <string name="menu_update_time">更新时间</string>
<string name="menu_hot">热度</string> <string name="menu_hot">热度</string>
@@ -111,6 +112,7 @@
<string name="button_sub_subscribed">已加书架</string> <string name="button_sub_subscribed">已加书架</string>
<string name="button_start">开始阅读</string> <string name="button_start">开始阅读</string>
<string name="button_more">更多</string> <string name="button_more">更多</string>
<string name="button_reload">重新加载</string>
<string name="text_format_hit">热度 %1$d</string> <string name="text_format_hit">热度 %1$d</string>
<string name="text_format_stat">状态 %1$s</string> <string name="text_format_stat">状态 %1$s</string>
@@ -135,6 +137,8 @@
<string name="settings_cat_general">通用</string> <string name="settings_cat_general">通用</string>
<string name="settings_cat_general_sb_title_startup_menu">启动时显示</string> <string name="settings_cat_general_sb_title_startup_menu">启动时显示</string>
<string name="settings_cat_general_sb_summary_startup_menu">默认主页</string> <string name="settings_cat_general_sb_summary_startup_menu">默认主页</string>
<string name="settings_cat_general_et_title_app_version">拷贝版本号</string>
<string name="settings_cat_general_et_summary_app_version">默认&appver;</string>
<string name="settings_cat_general_sb_card_per_row">每行加载卡片数偏移</string> <string name="settings_cat_general_sb_card_per_row">每行加载卡片数偏移</string>
<string name="settings_cat_general_sm_card_per_row">默认为0表示无偏移, 在此基础上加减</string> <string name="settings_cat_general_sm_card_per_row">默认为0表示无偏移, 在此基础上加减</string>
@@ -170,8 +174,6 @@
<string name="settings_cat_md_sw_show_0m_manga">显示未下载漫画</string> <string name="settings_cat_md_sw_show_0m_manga">显示未下载漫画</string>
<string name="settings_cat_md_sm_show_0m_manga">打开后将在我的下载显示所有浏览过详情页的漫画,旧版下载永远全部显示</string> <string name="settings_cat_md_sm_show_0m_manga">打开后将在我的下载显示所有浏览过详情页的漫画,旧版下载永远全部显示</string>
<string name="login_null_username">用户名为空</string> <string name="login_null_username">用户名为空</string>
<string name="login_null_pwd">密码为空</string> <string name="login_null_pwd">密码为空</string>
<string name="login_get_conn_failed">登录失败</string> <string name="login_get_conn_failed">登录失败</string>

View File

@@ -23,6 +23,17 @@
app:showSeekBarValue="true" app:showSeekBarValue="true"
app:summary="@string/settings_cat_general_sm_card_per_row" app:summary="@string/settings_cat_general_sm_card_per_row"
app:title="@string/settings_cat_general_sb_card_per_row" /> app:title="@string/settings_cat_general_sb_card_per_row" />
<EditTextPreference
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="@string/app_ver"
android:selectAllOnFocus="false"
android:singleLine="true"
android:title="@string/settings_cat_general_et_title_app_version"
android:summary="@string/settings_cat_general_et_summary_app_version"
app:enableCopying="true"
app:iconSpaceReserved="false"
app:key="settings_cat_general_et_app_version" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
app:iconSpaceReserved="false" app:iconSpaceReserved="false"