1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-06-10 18:40:30 +08:00
新增
1. 启动时尝试登陆失败提示
2. 热切换阅览模式
3. 拉进度条连续翻页超过3后松手时再更新进度
4. 更高清晰度支持 (可在设置调节)
修复
1. 大屏设备下用户头像过大
2. 阅览漫画时加载图片过快导致触发访问限制
3. 白色背景下无法显示页码标号
4. 闪退重新拉起时继续闪退
5. 非ViewPager阅读漫画异常CPU占用
优化
1. 默认api地址更改为api.copymanga.tv
2. 字符串与常量定义
3. 首页下拉刷新行为
4. 竖向、单页模式下漫画加载速度
5. 封面加载速度
This commit is contained in:
源文雨
2024-01-17 20:41:38 +09:00
parent 2257e977d1
commit 40574ba9a6
30 changed files with 356 additions and 174 deletions

View File

@@ -14,7 +14,7 @@
android:usesCleartextTraffic="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="@string/file_provider_authority"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
@@ -22,25 +22,25 @@
android:resource="@xml/provider_paths" />
</provider>
<activity
android:name="top.fumiama.copymanga.MainActivity"
android:name="${applicationId}.MainActivity"
android:theme="@style/AppTheme.NoActionBar"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="top.fumiama.copymanga.SHARE"/>
<action android:name="${applicationId}.SHARE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name="top.fumiama.copymanga.LoginActivity"
android:name="${applicationId}.LoginActivity"
android:theme="@style/AppTheme.NoActionBar"/>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="fullSensor"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<activity
android:name="top.fumiama.copymanga.ui.vm.ViewMangaActivity"
android:name="${applicationId}.ui.vm.ViewMangaActivity"
android:theme="@style/AppTheme.NoActionBar"/>
</application>

View File

@@ -69,8 +69,9 @@ class MainActivity : AppCompatActivity() {
private var isMenuWaiting = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.onCreate(null)
// must init before setContentView because HomeF need them to init
mainWeakReference = WeakReference(this)
toolsBox = UITools(this)

View File

@@ -31,7 +31,7 @@ object Reader {
}
if (zipf.exists()) {
ViewMangaActivity.zipFile = zipf
intent.putExtra("callFrom", "zipFirst")
//intent.putExtra("callFrom", "zipFirst")
startActivity(intent)
} else {
ViewMangaActivity.zipFile = null

View File

@@ -1,17 +1,12 @@
package top.fumiama.copymanga.template.ui
import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.net.Uri
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
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.request.RequestListener
import com.bumptech.glide.request.target.Target
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
@@ -21,6 +16,7 @@ import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.dmzj.copymanga.R
import java.io.File
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicInteger
class CardList(
private val fragment: WeakReference<Fragment>,
@@ -32,6 +28,7 @@ class CardList(
private var rows:Array<View?> = arrayOfNulls(20)
private var index = 0
private var count = 0
private var cardLoadingWaits = AtomicInteger()
var initClickListeners: InitClickListeners? = null
var exitCardList = false
@@ -115,9 +112,17 @@ class CardList(
if(!file.exists()){
if(head != null) {
that?.context?.let { context ->
Glide.with(context).load(
val waitMillis = cardLoadingWaits.getAndIncrement().toLong()*200
val g = Glide.with(context).load(
GlideUrl(CMApi.proxy?.wrap(head)?:head, CMApi.myGlideHeaders)
).addListener(GlideHideLottieViewListener(WeakReference(it.laic))).into(it.imic)
).addListener(GlideHideLottieViewListener(WeakReference(it.laic)) {
if (exitCardList) return@GlideHideLottieViewListener
cardLoadingWaits.decrementAndGet()
})
if (waitMillis > 0) it.imic.postDelayed({
if (exitCardList) return@postDelayed
g.into(it.imic)
}, waitMillis) else g.into(it.imic)
}
} else {
it.laic.pauseAnimation()

View File

@@ -7,11 +7,13 @@ import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.http.Proxy
import top.fumiama.copymanga.tools.http.Resolution
import java.io.File
import java.net.URLEncoder
object CMApi {
var proxy = if(Proxy.useImageProxy) Proxy(R.string.imgProxyApiUrl, R.string.imgProxyApiPrefix, R.string.imgProxyKeyID) else null
var resolution = Resolution(Regex("\\.c\\d+x\\."))
var myGlideHeaders: LazyHeaders? = null
get() {
MainActivity.mainWeakReference?.get()?.let {

View File

@@ -87,7 +87,7 @@ class DownloadPool(folder: String) {
var s = false
while (!s && tryTimes-- > 0) {
val u = imgUrls[index]
s = (DownloadTools.getHttpContent(CMApi.proxy?.wrap(u)?:u, -1))?.let {
s = (DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.proxy?.wrap(u)?:u), -1))?.let {
zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}"))
zip.write(it)
zip.closeEntry()

View File

@@ -124,6 +124,26 @@ object DownloadTools {
task
}
fun prepare(url: String?): FutureTask<ByteArray?>? =
url?.let {
Log.d("Mydl", "prepareHttp: $it")
var ret: ByteArray? = null
val task = FutureTask(Callable {
try {
val connection = getNormalConnection(it, "GET")
val ci = connection?.inputStream
ret = ci?.readBytes()
ci?.close()
connection?.disconnect()
} catch (ex: Exception) {
ex.printStackTrace()
}
return@Callable ret
})
task
}
/*private fun replaceChineseCharacters(string: String?) : String? {
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.M) return string
else return string?.replace(Regex("(?<=/)[\\w\\s\\d\\u4e00-\\u9fa5.-]+(?=/?)")) { match ->

View File

@@ -35,7 +35,7 @@ class Proxy(id: Int, apiPrefixID: Int, keyID: Int? = null) {
}
return false
}
val useApiProxy: Boolean
/*val useApiProxy: Boolean
get() {
MainActivity.mainWeakReference?.get()?.let {
PreferenceManager.getDefaultSharedPreferences(it).apply {
@@ -45,6 +45,6 @@ class Proxy(id: Int, apiPrefixID: Int, keyID: Int? = null) {
}
}
return false
}
}*/
}
}

View File

@@ -0,0 +1,20 @@
package top.fumiama.copymanga.tools.http
import androidx.preference.PreferenceManager
import top.fumiama.copymanga.MainActivity
import top.fumiama.dmzj.copymanga.R
class Resolution(private val original: Regex) {
private val imageResolution: Int
get() {
MainActivity.mainWeakReference?.get()?.apply {
PreferenceManager.getDefaultSharedPreferences(this).apply {
val b = getString(getString(R.string.imgResolutionKeyID), null)
//Log.d("MyResolution", "use image resolution: $b")
return b?.toInt()?:1500
}
}
return 1500
}
fun wrap(u: String) : String = u.replace(original, ".c${imageResolution}x.")
}

View File

@@ -9,7 +9,7 @@ import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import java.lang.ref.WeakReference
class GlideHideLottieViewListener(private val wla: WeakReference<LottieAnimationView>): RequestListener<Drawable> {
class GlideHideLottieViewListener(private val wla: WeakReference<LottieAnimationView>, private val runAfterLoad: (() -> Unit)? = null): RequestListener<Drawable> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
@@ -29,6 +29,7 @@ class GlideHideLottieViewListener(private val wla: WeakReference<LottieAnimation
wla.get()?.apply {
pauseAnimation()
visibility = View.GONE
runAfterLoad?.let { it() }
}
return false
}

View File

@@ -24,8 +24,6 @@ import java.lang.Thread.sleep
import java.lang.ref.WeakReference
class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
var fbibinfo: View? = null
var fbtinfo: View? = null
var isOnPause = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@@ -73,9 +73,8 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
//0 -> setLayouts()
1 -> setCover()
2 -> setTexts()
3 -> that?.fbibinfo?.let { setInfoHeight(it) }
4 -> setAuthorsAndTags()
5 -> setOverScale()
3 -> setAuthorsAndTags()
4 -> setOverScale()
6 -> if(complete) that?.navigate2dl()
7 -> setVolumes()
8 -> that?.apply { fbl?.addView(msg.obj as View) }
@@ -102,7 +101,6 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
override fun doWhenFinishDownload() {
super.doWhenFinishDownload()
if(exit) return
inflateComponents()
if(keys.isEmpty()) book?.results?.groups?.values?.forEach{
keys += it.name
gpws += it.path_word
@@ -112,7 +110,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
cnts += it.count
Log.d("MyBFH", "Add caption: ${it.name} @ ${it.path_word} of ${it.count}")
}
for (i in 1..5) {
for (i in 1..4) {
sendEmptyMessageDelayed(i, (100*i).toLong())
}
if(vols?.isEmpty() != false) initComicData()
@@ -126,24 +124,15 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
that?.setAddToShelf()
Log.d("MyBH", "Set complete: true")
}
private fun inflateComponents(){
if(that?.fbibinfo == null) that?.fbibinfo = that?.layoutInflater?.inflate(R.layout.line_bookinfo, that?.fbl, false)
if(that?.fbtinfo == null) that?.fbtinfo = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.fbl, false)
}
private fun setOverScale(){
that?.fbov?.setScaleView(that!!.lbibg)
}
private fun setCover(){
private fun setCover() {
that?.apply {
try {
fbl.addView(fbibinfo)
} catch (e: Exception) {
e.printStackTrace()
(fbibinfo?.parent as LinearLayout?)?.removeAllViews()
fbl?.addView(fbibinfo)
that?.layoutInflater?.inflate(R.layout.line_bookinfo, that?.fbl, false)?.let {
fbl.addView(it)
setInfoHeight(it)
}
book?.results?.comic?.cover?.let { cover ->
val load = Glide.with(this).load(
@@ -180,8 +169,9 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
book?.results?.comic?.status?.display
) }?:""
that?.bttime?.text = book?.results?.comic?.datetime_updated
(that?.fbtinfo as TextView).text = book?.results?.comic?.brief
that?.fbl?.addView(that?.fbtinfo)
val v = that?.layoutInflater?.inflate(R.layout.line_text_info, that?.fbl, false)
(v as TextView).text = book?.results?.comic?.brief
that?.fbl?.addView(v)
that?.fbl?.addView(divider)
}

View File

@@ -352,7 +352,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
it.tbtn.setBackgroundResource(R.drawable.rndbg_checked)
it.tbtn.isChecked = false
ViewMangaActivity.zipFile = zipf
ViewMangaActivity.dlhandler = this
ViewMangaActivity.dlHandler = this
ViewMangaActivity.position = it.tbtn.index
dl?.show()
val intent = Intent(that?.context, ViewMangaActivity::class.java)
@@ -380,7 +380,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
toolsBox.buildInfo("直接观看", "不下载而进行观看", "确定",
null, "取消", {
ViewMangaActivity.zipFile = null
ViewMangaActivity.dlhandler = this
ViewMangaActivity.dlHandler = this
ViewMangaActivity.position = it.tbtn.index
dl?.show()

View File

@@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageButton
import android.widget.Toast
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -41,6 +42,19 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if(isFirstInflate) {
val tb = mainWeakReference?.get()?.toolsBox
val netInfo = tb?.netInfo
if(netInfo != null && netInfo != tb.transportStringNull && netInfo != tb.transportStringError) Thread {
val l = MainActivity.member?.refreshAvatar()
if (l?.code != 200) {
mainWeakReference?.get()?.runOnUiThread {
Toast.makeText(context, "${getString(R.string.login_get_avatar_failed)}: 代码${l?.code}, 信息: ${l?.message}", Toast.LENGTH_SHORT).show()
}
MainActivity.member?.logout()
}
}.start()
homeHandler = HomeHandler(WeakReference(this))
val theme = resources.newTheme()
swiperefresh?.setColorSchemeColors(
resources.getColor(R.color.colorAccent, theme),
@@ -150,20 +164,6 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
}.start()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val tb = mainWeakReference?.get()?.toolsBox
val netInfo = tb?.netInfo
if(netInfo != null && netInfo != tb.transportStringNull && netInfo != tb.transportStringError) Thread {
val l = MainActivity.member?.refreshAvatar()
if (l?.code != 200) {
MainActivity.member?.logout()
}
}.start()
homeHandler = HomeHandler(WeakReference(this))
}
override fun onDestroy() {
super.onDestroy()
homeHandler.destroy()

View File

@@ -12,6 +12,7 @@ import android.widget.LinearLayout
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.animation.doOnEnd
import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
@@ -43,9 +44,9 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
var fhib: View? = null
get() {
Log.d("MyHH", "Get fhib.")
if(field == null){
if (field == null) {
field = homeF?.layoutInflater?.inflate(R.layout.viewpage_banner, homeF?.fhl, false)
Thread{homeF?.homeHandler?.sendEmptyMessage(3)}.start()
Thread{ homeF?.homeHandler?.sendEmptyMessage(3) }.start()
}
return field
}
@@ -57,17 +58,16 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
-1 -> homeF?.swiperefresh?.isRefreshing = msg.obj as Boolean
//0 -> setLayouts()
1 -> inflateCardLines()
3 -> setBanner(fhib as Banner)
5 -> setBannerInfo(msg.obj as Banner)
6 -> {
homeF?.fhl?.let {
ObjectAnimator.ofFloat(it, "alpha", 1f, 0f).setDuration(233).start()
it.postDelayed({
val oa = ObjectAnimator.ofFloat(it, "alpha", 1f, 0f).setDuration(233)
oa.doOnEnd { _ ->
it.removeAllViews()
ObjectAnimator.ofFloat(it, "alpha", 0f, 1f).setDuration(233).start()
}, 233)
it.alpha = 1f
}
oa.start()
}
}
7 -> inflateBanner()
@@ -213,7 +213,7 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
}
}
private fun inflateCardLines() = Thread{
private fun inflateCardLines() = Thread {
if (indexLines.isNotEmpty()) indexLines = arrayOf()
inflateRec()
inflateTopics()

View File

@@ -84,9 +84,9 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
PREPARE_LAST_PAGE -> wv.get()?.prepareLastPage(msg.arg1, msg.arg2)
DIALOG_SHOW -> dl.show()
LOAD_ITEM_SCROLL_MODE -> loadScrollMode(msg.arg1)
LOAD_ITEM_SCROLL_MODE -> loadScrollMode(msg.arg1, msg.obj as? Runnable?)
LOAD_SCROLL_MODE -> loadScrollMode()
LOAD_ITEM_IMAGES_INTO_LINE -> loadImagesIntoLine(msg.arg1)
LOAD_ITEM_IMAGES_INTO_LINE -> loadImagesIntoLine(msg.arg1, msg.obj as? Runnable?)
LOAD_IMAGES_INTO_LINE -> loadImagesIntoLine()
RESTORE_PAGE_NUMBER -> {
sendEmptyMessage(DIALOG_HIDE)
@@ -121,6 +121,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
}
Log.d("MyVMH", "remainingImageCount = $remainingImageCount")
}
DO_LAMBDA -> (msg.obj as? Runnable?)?.run()
SET_NET_INFO -> wv.get()?.idtime?.text = SimpleDateFormat("HH:mm").format(Date()) + week + wv.get()?.toolsBox?.netInfo
}
}
@@ -187,7 +188,8 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
wv.get()?.initManga()
wv.get()?.vprog?.visibility = View.GONE
}
private fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)) = Thread{
private fun loadImagesIntoLine(item: Int = (wv.get()?.currentItem?:0), doAfter: Runnable? = null) = Thread{
val maxCount: Int = (wv.get()?.verticalLoadMaxCount?:20)
Log.d("MyVMH", "Fun: loadImagesIntoLine($item, $maxCount)")
wv.get()?.realCount?.let { count ->
if(count > 0){
@@ -195,10 +197,15 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
val loadCount = (if(notFull) count - item else maxCount) - 1
obtainMessage(INIT_IMAGE_COUNT, loadCount+1, 0).sendToTarget()
Log.d("MyVMH", "count: $count, loadCount: $loadCount, notFull: $notFull")
if(loadCount >= 0) for(i in 0..loadCount) obtainMessage(LOAD_IMG_ON,item + i, if(i == loadCount - 1) 1 else 0, wv.get()?.scrollImages?.get(i)).sendToTarget()
if(loadCount >= 0) for(i in 0..loadCount) {
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)
if(notFull) obtainMessage(PREPARE_LAST_PAGE, loadCount + 1, maxCount).sendToTarget()
wv.get()?.let { it.runOnUiThread { it.updateSeekBar() } }
obtainMessage(DO_LAMBDA, Runnable{
doAfter?.run()
wv.get()?.let { it.updateSeekBar(0) }
}).sendToTarget()
}
}
}.start()
@@ -209,11 +216,11 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
sendEmptyMessage(LOAD_IMAGES_INTO_LINE)
}
private fun loadScrollMode(item: Int) {
private fun loadScrollMode(item: Int, doAfter: Runnable? = null) {
sendEmptyMessage(DIALOG_SHOW)
//sleep(233)
Log.d("MyVMH", "loadImgsIntoLine($item)")
obtainMessage(LOAD_ITEM_IMAGES_INTO_LINE, item, 0).sendToTarget()
obtainMessage(LOAD_ITEM_IMAGES_INTO_LINE, item, 0, doAfter).sendToTarget()
}
private fun showInfCard() {
@@ -258,7 +265,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
const val TRIGGER_INFO_CARD_FULL = 18
const val INIT_IMAGE_COUNT = 19
const val DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO = 20
const val DO_LAMBDA = 21
const val SET_NET_INFO = 22
}
}

View File

@@ -13,9 +13,11 @@ import android.media.AudioManager
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.util.TypedValue
import android.view.*
import android.widget.SeekBar
import android.widget.Toast
import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.preference.PreferenceManager
@@ -50,6 +52,7 @@ import java.io.File
import java.io.InputStream
import java.lang.ref.WeakReference
import java.util.concurrent.FutureTask
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipFile
import kotlin.math.abs
@@ -78,16 +81,23 @@ class ViewMangaActivity : TitleActivityTemplate() {
set(value) = setPageNumber(value)
//var pn = 0
private val isPnValid: Boolean get() {
val re = if(pn == -2) {
val re = forceLetPNValid || if(pn == -2) {
pn = 0
true
} else {
intent.getStringExtra("function") == "log" && pn > 0
}
Log.d("MyVM", "isPnValid: $re")
return re
return re && pn <= realCount
}
private var forceLetPNValid: Boolean = false
get() {
if(!field) return false
field = false
return true
}
private var tasks: Array<FutureTask<ByteArray?>?>? = null
private var tasksRunStatus: Array<Boolean>? = null
private var destroy = false
private var cut = false
private var isCut = booleanArrayOf()
@@ -100,10 +110,26 @@ class ViewMangaActivity : TitleActivityTemplate() {
var urlArray = arrayOf<String>()
private val loadImgOnWait = AtomicInteger()
private var colorOnSurface: Int = 0
get() {
if (field != 0) return field
val tv = TypedValue()
field = if (theme.resolveAttribute(R.attr.colorOnSurface, tv, true)) {
Log.d("MyVM", "resolve R.attr.colorOnSurface: ${tv.data}")
tv.data
} else {
ContextCompat.getColor(applicationContext, R.color.material_on_surface_stroke)
}
return field
}
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
postponeEnterTransition()
setContentView(R.layout.activity_viewmanga)
super.onCreate(savedInstanceState)
super.onCreate(null)
val settingsPref = MainActivity.mainWeakReference?.get()?.let { PreferenceManager.getDefaultSharedPreferences(it) }
va = WeakReference(this)
//dlZip2View = intent.getStringExtra("callFrom") == "Dl" || p["dlZip2View"] == "true"
@@ -134,6 +160,8 @@ class ViewMangaActivity : TitleActivityTemplate() {
e.printStackTrace()
toolsBox.toastError(R.string.load_manga_error)
}
startPostponedEnterTransition()
ObjectAnimator.ofFloat(vcp, "alpha", 0.1f, 1f).setDuration(1000).start()
}
@Suppress("DEPRECATION")
@@ -183,35 +211,13 @@ class ViewMangaActivity : TitleActivityTemplate() {
setProgress()
}
private fun preDownloadChapterPages() {
private fun prepareDownloadTasks() {
getImgUrlArray()?.let {
val mid = (if(pn in 1 until realCount) (if(cut) 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 ->
it[i]?.let { u ->
tasks[i] = DownloadTools.touch(CMApi.proxy?.wrap(u)?:u)
Thread.sleep(1000)
}
}
}
}.start()
Thread.sleep(500)
Thread{
for (i in left downTo 0) {
if(destroy) break
tasks?.let { tasks ->
it[i]?.let { u ->
tasks[i] = DownloadTools.touch(CMApi.proxy?.wrap(u)?:u)
Thread.sleep(1000)
}
}
}
}.start()
tasks = Array(it.size) { i ->
val u = it[i]?:return@Array null
return@Array DownloadTools.prepare(CMApi.resolution.wrap(CMApi.proxy?.wrap(u)?:u))
}
tasksRunStatus = Array(it.size) { return@Array false }
}
}
@@ -226,7 +232,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
forEachIndexed{ i, it ->
if(it != null) {
Thread{
DownloadTools.getHttpContent(CMApi.proxy?.wrap(it)?:it, 1024)?.inputStream()?.let {
DownloadTools.getHttpContent(CMApi.resolution.wrap(CMApi.proxy?.wrap(it)?:it), 1024)?.inputStream()?.let {
isCut[i] = canCut(it)
analyzedCnt[i] = true
}
@@ -245,7 +251,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
count = size
runOnUiThread { prepareItems() }
preDownloadChapterPages()
if (notUseVP) prepareDownloadTasks()
}
}
@@ -379,7 +385,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
private fun loadImgUrlInto(imgView: ScaleImageView, url: String, useCut: Boolean, isLeft: Boolean){
Log.d("MyVM", "Load from adt: $url")
AutoDownloadThread(CMApi.proxy?.wrap(url)?:url, 1000) {
AutoDownloadThread(CMApi.resolution.wrap(CMApi.proxy?.wrap(url)?:url), 1000) {
it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) }
}.start()
}
@@ -388,7 +394,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
val loading = Bitmap.createBitmap(1024, 256, Bitmap.Config.ARGB_8888)
val canvas = Canvas(loading)
val paint = Paint()
paint.color = ContextCompat.getColor(applicationContext, R.color.design_default_color_surface)
paint.color = colorOnSurface
paint.textSize = 100.0f
paint.typeface = Font.nisiTypeFace!!
val text = "${position+1}"
@@ -398,8 +404,9 @@ class ViewMangaActivity : TitleActivityTemplate() {
return loading
}
fun loadImgOn(imgView: ScaleImageView, position: Int){
fun loadImgOn(imgView: ScaleImageView, position: Int) {
Log.d("MyVM", "Load img: $position")
if (position < 0 || position > realCount) return
val index2load = if(cut) abs(indexMap[position]) -1 else position
val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[position] > 0
@@ -408,18 +415,53 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
else {
loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
val re = tasks?.get(index2load)
if (re != null) Thread{
val data = re.get()
if(data != null && data.isNotEmpty()) {
BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
loadImg(imgView, it, useCut, isLeft, false)
Log.d("MyVM", "Load position $position from task")
}?:Log.d("MyVM", "null bitmap at $position")
val sleepTime = loadImgOnWait.getAndIncrement().toLong()*200
Log.d("MyVM", "loadImgOn sleep: $sleepTime ms")
Thread {
val re = tasks?.get(index2load)
if (sleepTime > 0 && re?.isDone != true) Thread.sleep(sleepTime)
if (re != null) {
if(!re.isDone) re.run()
val data = re.get()
if(data != null && data.isNotEmpty()) {
BitmapFactory.decodeByteArray(data, 0, data.size)?.let {
loadImg(imgView, it, useCut, isLeft, false)
runOnUiThread { Log.d("MyVM", "Load position $position from task") }
}?:runOnUiThread { Log.d("MyVM", "null bitmap at $position") }
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
}
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
loadImgOnWait.decrementAndGet()
tasks?.apply {
if (index2load >= size) return@apply
val p = if (index2load == size-1) index2load-1 else index2load+1
var delta = 1
var isMinus = false
var pos = p
var maxCount = size
while (pos in indices && get(pos)?.isDone != false && tasksRunStatus?.get(pos) != false && maxCount-- > 0) {
runOnUiThread { Log.d("MyVM", "search $pos") }
pos = p + if (isMinus) -delta else delta
if (pos !in indices) {
isMinus = !isMinus
if (!isMinus) delta++
pos = p + if (isMinus) -delta else delta
if (pos !in indices) return@apply
}
isMinus = !isMinus
if (!isMinus) delta++
}
if (pos !in indices || tasksRunStatus?.get(pos) != false) return@apply
runOnUiThread { Log.d("MyVM", "Preload position $pos from task") }
get(pos)?.apply {
if(!isDone) {
tasksRunStatus?.set(pos, true)
run()
}
}
}
}.start()
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
}
imgView.visibility = View.VISIBLE
}
@@ -516,23 +558,43 @@ class ViewMangaActivity : TitleActivityTemplate() {
idtbcut.isChecked = cut
idtbcut.setOnClickListener {
pb["useCut"] = idtbcut.isChecked
Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000)
oa.doOnEnd {
recreate()
}
oa.start()
}
}
private fun prepareIdBtLR() {
idtblr.isChecked = r2l
idtblr.setOnClickListener {
if (isVertical) {
Toast.makeText(this, R.string.unsupported_mode_switching, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
pb["r2l"] = idtblr.isChecked
Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000)
oa.doOnEnd {
recreate()
}
oa.start()
}
}
private fun prepareIdBtVP() {
idtbvp.isChecked = notUseVP
idtbvp.setOnClickListener {
if (isVertical) {
Toast.makeText(this, R.string.unsupported_mode_switching, Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
pb["noVP"] = idtbvp.isChecked
Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000)
oa.doOnEnd {
recreate()
}
oa.start()
}
}
@@ -554,7 +616,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
}
fun updateSeekBar() {
fun updateSeekBar(p: Int = 0) {
if (p > 0) {
updateSeekText(p)
return
}
if (!isInSeek) hideDrawer()
updateSeekText()
updateSeekProgress()
@@ -569,19 +635,53 @@ class ViewMangaActivity : TitleActivityTemplate() {
inftitle.ttitle.text = handler.manga?.results?.chapter?.name
inftxtprogress.text = "$pageNum/$realCount"
infseek.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
var p = 0
var manualCount = 0
var startP = 0
override fun onProgressChanged(p0: SeekBar?, p1: Int, isHuman: Boolean) {
Log.d("MyVM", "seek to ${p1 * realCount / 100}")
if (isHuman) {
if (p1 >= (pageNum + 1) * 100 / realCount) scrollForward()
else if (p1 < (pageNum - 1) * 100 / realCount) scrollBack()
var np = p1 * realCount / 100
if (np <= 0) np = 1
else if (np > realCount) np = realCount
Log.d("MyVM", "seek to $np")
if (p1 >= (pageNum + 1) * 100 / realCount) {
if(manualCount < 3) scrollForward() else p = np
after()
}
else if (p1 < (pageNum - 1) * 100 / realCount) {
if(manualCount < 3) scrollBack() else p = np
after()
}
}
}
override fun onStartTrackingTouch(p0: SeekBar?) {
isInSeek = true
p = pageNum
startP = p
manualCount = 0
}
override fun onStopTrackingTouch(p0: SeekBar?) {
isInSeek = false
if(manualCount >= 3) {
val pS = p
Log.d("MyVM", "stop seek at $pS")
if (isVertical && startP/verticalLoadMaxCount != p/verticalLoadMaxCount) {
handler.obtainMessage(
VMHandler.LOAD_ITEM_SCROLL_MODE,
p / verticalLoadMaxCount * verticalLoadMaxCount,
0,
Runnable {
isInScroll = false
forceLetPNValid = true
pn = pS
Log.d("MyVM", "set stopped seek to $pS = $pageNum")
isInSeek = false
}
).sendToTarget()
} else pageNum = pS
} else isInSeek = false
}
private fun after() {
if(manualCount++ < 3) p = pageNum else updateSeekBar(p)
}
})
isearch.setImageResource(R.drawable.ic_author)
@@ -617,7 +717,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
handler.sendEmptyMessage(if(isPnValid) VMHandler.LOAD_PAGE_FROM_ITEM else VMHandler.LOAD_SCROLL_MODE)
psivs.setOnScrollChangeListener { _, _, scrollY, _, _ ->
isInScroll = true
if(!isInSeek){
if(!isInSeek) {
val delta = (scrollY.toFloat() * size.toFloat() / psivl.height.toFloat() + 0.5).toInt() - currentItem % verticalLoadMaxCount
if(delta != 0 && !(delta > 0 && pageNum == size)) {
pageNum += delta
@@ -628,28 +728,48 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
idtbvh.setOnClickListener {
pb["vertical"] = idtbvh.isChecked
Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
val oa = ObjectAnimator.ofFloat(vcp, "alpha", 1f, 0.1f).setDuration(1000)
oa.doOnEnd {
recreate()
}
oa.start()
}
}
fun scrollBack() {
isInScroll = false
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0){
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) {
Log.d("MyVM", "Do scroll back, isVertical: $isVertical, pageNum: $pageNum")
handler.obtainMessage(VMHandler.LOAD_ITEM_SCROLL_MODE, currentItem - verticalLoadMaxCount, 0).sendToTarget() //loadImgsIntoLine(currentItem - verticalLoadMaxCount)
psivl.postDelayed({ pageNum-- }, 233)
if (isInSeek) {
updateSeekBar(pageNum-1)
return
}
handler.obtainMessage(
VMHandler.LOAD_ITEM_SCROLL_MODE,
currentItem - verticalLoadMaxCount, 0,
Runnable{
forceLetPNValid = true
pn = pageNum-1
}
).sendToTarget() //loadImgsIntoLine(currentItem - verticalLoadMaxCount)
} else pageNum--
}
fun scrollForward() {
isInScroll = false
pageNum++
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE)
if(isVertical && (pageNum-1) % verticalLoadMaxCount == 0) {
if (isInSeek) {
updateSeekBar(pageNum+1)
return
}
handler.sendEmptyMessage(VMHandler.LOAD_SCROLL_MODE)
}
}
@SuppressLint("SetTextI18n")
private fun updateSeekText() {
inftxtprogress.text = "$pageNum/$realCount"
private fun updateSeekText(p: Int = 0) {
inftxtprogress.text = "${if(p == 0) pageNum else p}/$realCount"
}
private fun updateSeekProgress() {
@@ -657,10 +777,10 @@ class ViewMangaActivity : TitleActivityTemplate() {
}
override fun onDestroy() {
dlhandler?.sendEmptyMessage(0)
dlHandler?.sendEmptyMessage(0)
tt.canDo = false
destroy = true
dlhandler = null
dlHandler = null
handler.dl.dismiss()
handler.destroy()
super.onDestroy()
@@ -691,7 +811,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
val thisOneI = holder.itemView.onei
Glide.with(this@ViewMangaActivity.applicationContext)
.asBitmap()
.load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders))
.load(GlideUrl(CMApi.resolution.wrap(CMApi.proxy?.wrap(it)?:it), CMApi.myGlideHeaders))
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
@@ -700,7 +820,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
override fun onLoadCleared(placeholder: Drawable?) { }
})
} else Glide.with(this@ViewMangaActivity.applicationContext)
.load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders))
.load(GlideUrl(CMApi.resolution.wrap(CMApi.proxy?.wrap(it)?:it), CMApi.myGlideHeaders))
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.into(holder.itemView.onei)
}
@@ -745,7 +865,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
var fileArray = arrayOf<File>()
var position = 0
var zipFile: File? = null
var dlhandler: Handler? = null
var dlHandler: Handler? = null
var va: WeakReference<ViewMangaActivity>? = null
var pn = 0
var noCellarAlert = false

View File

@@ -20,7 +20,8 @@ class ScrollRefreshView : NestedScrollView {
override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
super.onScrollChanged(l, t, oldl, oldt)
//Log.d("MyOSV", "$l, $t, $oldl, $oldt")
swipeRefreshLayout?.isEnabled = t == 0
if(swipeRefreshLayout?.isRefreshing == false) {
swipeRefreshLayout?.isEnabled = t == 0
}
}
}

View File

@@ -3,7 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/vcp"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:alpha="0.1">
<include
android:id="@+id/vone"
@@ -35,7 +36,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" >
app:layout_constraintTop_toTopOf="parent">
</androidx.viewpager2.widget.ViewPager2>

View File

@@ -16,8 +16,8 @@
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="@dimen/global_radius"
app:cardElevation="@dimen/global_card_elevation"
app:cardCornerRadius="@dimen/book_card_radius"
app:cardElevation="@dimen/book_card_elevation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -15,8 +15,8 @@
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="@dimen/global_radius"
app:cardElevation="@dimen/global_card_elevation"
app:cardCornerRadius="@dimen/book_card_radius"
app:cardElevation="@dimen/book_card_elevation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout 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:layout_width="match_parent"
@@ -12,7 +12,8 @@
android:id="@+id/swiperefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="64dp">
android:isScrollContainer="true"
android:layout_marginTop="@dimen/search_layout_padding">
<top.fumiama.copymanga.views.ScrollRefreshView
android:id="@+id/fhov"

View File

@@ -8,7 +8,7 @@
<ImageView
android:id="@+id/navhbg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="match_parent"
android:foreground="@drawable/mask_blackbottom"
android:onClick="onNavHBgClicked"
android:scaleType="centerCrop"
@@ -41,10 +41,10 @@
<ImageView
android:id="@+id/navhicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="@dimen/user_icon_size"
android:layout_height="@dimen/user_icon_size"
android:layout_marginBottom="@dimen/nav_header_vertical_spacing"
android:alpha="@dimen/global_alpha"
android:alpha="@dimen/user_icon_alpha"
android:onClick="startLoginActivity"
app:layout_constraintBottom_toTopOf="@+id/navttitle"
app:layout_constraintEnd_toEndOf="parent"

View File

@@ -15,8 +15,8 @@
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="@dimen/global_radius"
app:cardElevation="@dimen/global_card_elevation"
app:cardCornerRadius="@dimen/book_card_radius"
app:cardElevation="@dimen/book_card_elevation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@@ -1,5 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="search_types">
<item>全部</item>
<item>名称</item>
<item>作者</item>
<item>汉化组</item>
</string-array>
<string-array name="weeks">
<item>周日</item>
<item>周一</item>
@@ -9,4 +15,9 @@
<item>周五</item>
<item>周六</item>
</string-array>
<string-array name="resolutions">
<item>1500</item>
<item>1200</item>
<item>800</item>
</string-array>
</resources>

View File

@@ -7,10 +7,11 @@
<dimen name="icon_size">32dp</dimen>
<dimen name="icon_size_middle">24dp</dimen>
<dimen name="icon_size_small">16dp</dimen>
<dimen name="user_icon_size">64dp</dimen>
<dimen name="user_icon_alpha">0.8</dimen>
<dimen name="global_alpha">0.8</dimen>
<dimen name="global_radius">16dp</dimen>
<dimen name="global_card_elevation">4dp</dimen>
<dimen name="book_card_radius">16dp</dimen>
<dimen name="book_card_elevation">4dp</dimen>
<dimen name="global_content_padding_bottom">48dp</dimen>
<dimen name="search_layout_padding">64dp</dimen>
</resources>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="search_types">
<item>全部</item>
<item>名称</item>
<item>作者</item>
<item>汉化组</item>
</string-array>
</resources>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
<!ENTITY hosturl "api.mangacopy.com">
<!ENTITY hosturl "api.copymanga.tv">
]>
<resources>
<string name="app_name">拷贝漫画</string>
<string name="file_provider_authority">top.fumiama.copymanga.fileprovider</string>
<string name="action_settings">设定</string>
<string name="action_info">关于</string>
@@ -42,7 +41,7 @@
<string name="web_error">网络错误</string>
<string name="download_cover_failed">保存封面失败</string>
<string name="download_cover_timeout">保存封面超时</string>
<string name="take_effect_on_reload">下次浏览生效</string>
<string name="unsupported_mode_switching">不支持在此模式下切换</string>
<string name="end_of_chapter">已经到头了~</string>
<string name="press_again_to_load_previous_chapter">再次按下加载上一章</string>
<string name="press_again_to_load_next_chapter">再次按下加载下一章</string>
@@ -85,6 +84,7 @@
<string name="apiProxyApiUrl">https://copymanga.azurewebsites.net/api/api?url=%1$s</string>
<string name="apiProxyApiPrefix">https://api.mangacopy.com/api/</string>
-->
<string name="imgResolutionKeyID">settings_cat_net_sb_image_resolution</string>
<string name="complete">已完结</string>
@@ -129,6 +129,8 @@
<string name="caption">标签</string>
<string name="settings_cat_net">网络</string>
<string name="settings_cat_net_sb_title_image_resolution">图片分辨率</string>
<string name="settings_cat_net_sb_summary_image_resolution">默认1500</string>
<string name="settings_cat_net_sw_use_cellar">总是使用流量观看</string>
<string name="settings_cat_net_sm_use_cellar">打开后不再在开始阅读时提示</string>
<string name="settings_cat_net_sw_use_foreign">使用海外线路</string>

View File

@@ -4,6 +4,16 @@
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="@string/settings_cat_net">
<ListPreference
android:max="1500"
app:iconSpaceReserved="false"
app:key="settings_cat_net_sb_image_resolution"
app:selectable="true"
app:summary="@string/settings_cat_net_sb_summary_image_resolution"
app:title="@string/settings_cat_net_sb_title_image_resolution"
app:entries="@array/resolutions"
app:entryValues="@array/resolutions"
android:defaultValue="1500"/>
<SwitchPreferenceCompat
app:iconSpaceReserved="false"
app:key="settings_cat_net_sw_use_cellar"