1
0
mirror of https://github.com/fumiama/copymanga.git synced 2026-07-02 08:40:25 +08:00
新增
1. 从断点继续下载漫画
2. 封面加载动画
3. 长按下载漫画导航至对应文件夹
修复
1. 部分下载漫画时的闪退
2. 搜索退出后不保留关键词
优化
1. 漫画阅读器代码
2. 每次启动时如未登录则不再刷新用户信息
3. AppBar 不跟随滚动 (fix #40)
4. 标签、作者、已完结默认从新到旧显示
升级
1. 升级支持库版本
This commit is contained in:
源文雨
2024-01-13 01:55:56 +09:00
parent 279e08b06a
commit 2257e977d1
31 changed files with 417 additions and 224 deletions

View File

@@ -1,6 +1,7 @@
<component name="ProjectDictionaryState"> <component name="ProjectDictionaryState">
<dictionary name="fumiama"> <dictionary name="fumiama">
<words> <words>
<w>imgs</w>
<w>lowpan</w> <w>lowpan</w>
<w>nisi</w> <w>nisi</w>
</words> </words>

View File

@@ -8,8 +8,8 @@ android {
applicationId 'top.fumiama.copymanga' applicationId 'top.fumiama.copymanga'
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 34 targetSdkVersion 34
versionCode 41 versionCode 42
versionName '2.0.5' versionName '2.0.6'
resConfigs 'zh', 'zh-rCN' resConfigs 'zh', 'zh-rCN'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -58,10 +58,10 @@ dependencies {
implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.10.0' implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5' implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.5' implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation 'com.afollestad.material-dialogs:input:3.3.0' implementation 'com.afollestad.material-dialogs:input:3.3.0'
@@ -74,5 +74,6 @@ dependencies {
implementation 'com.liaoinstan.springview:library:1.7.0' implementation 'com.liaoinstan.springview:library:1.7.0'
implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1' implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1'
implementation 'com.lapism:search:2.4.1@aar' implementation 'com.lapism:search:2.4.1@aar'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
implementation 'com.airbnb.android:lottie:6.3.0'
} }

View File

@@ -14,7 +14,7 @@
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="top.fumiama.copymanga.fileprovider" android:authorities="@string/file_provider_authority"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data

View File

@@ -21,19 +21,24 @@ class MangaDlTools {
fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int) { fun downloadChapterInVol(url: CharSequence, chapterName: CharSequence, group: CharSequence, index: Int) {
Log.d("MyMDT", "下载:$url, index$index") Log.d("MyMDT", "下载:$url, index$index")
AutoDownloadThread(url.toString()){ data -> AutoDownloadThread(url.toString(), 1000) { data ->
try {
Gson().fromJson(data?.decodeToString(), Chapter2Return::class.java)?.let { Gson().fromJson(data?.decodeToString(), Chapter2Return::class.java)?.let {
getChapterInfo(it, index, chapterName, group) getChapterInfo(it, index, chapterName, group)
} }
} catch (e: Exception) {
e.printStackTrace()
onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error")
}
}.start() }.start()
} }
@Synchronized private fun prepareDownloadListener() { @Synchronized private fun prepareDownloadListener() {
pool?.setOnDownloadListener { fileName: String, isSuccess: Boolean -> pool?.setOnDownloadListener { fileName: String, isSuccess: Boolean, message: String ->
indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, isSuccess) } indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, isSuccess, message) }
} }
pool?.setOnPageDownloadListener { fileName: String, downloaded: Int, total: Int, isSuccess: Boolean -> pool?.setOnPageDownloadListener { fileName: String, downloaded: Int, total: Int, isSuccess: Boolean, message: String ->
indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, downloaded, total, isSuccess) } indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, downloaded, total, isSuccess, message) }
} }
} }
@@ -83,7 +88,7 @@ class MangaDlTools {
var onDownloadedListener: OnDownloadedListener? = null var onDownloadedListener: OnDownloadedListener? = null
interface OnDownloadedListener{ interface OnDownloadedListener{
fun handleMessage(index: Int, isSuccess: Boolean) fun handleMessage(index: Int, isSuccess: Boolean, message: String)
fun handleMessage(index: Int, downloaded: Int, total: Int, isSuccess: Boolean) fun handleMessage(index: Int, downloaded: Int, total: Int, isSuccess: Boolean, message: String)
} }
} }

View File

@@ -4,14 +4,16 @@ import android.util.Log
import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference
import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import kotlin.random.Random
class AutoDownloadThread(private val url: String, private val whenFinish: (result: ByteArray?)->Unit): Thread() { class AutoDownloadThread(private val url: String, private val waitMilliseconds: Long = 0, private val whenFinish: (result: ByteArray?)->Unit): Thread() {
var exit = false var exit = false
override fun run() { override fun run() {
super.run() super.run()
var re: ByteArray? = null var re: ByteArray? = null
var c = 0 var c = 0
while (!exit && re == null && c++ < 3) { while (!exit && re == null && c++ < 3) {
if (waitMilliseconds > 0) sleep(200+Random.nextLong(waitMilliseconds))
re = DownloadTools.getHttpContent(url, re = DownloadTools.getHttpContent(url,
mainWeakReference?.get()?.getString(R.string.referer)!!, mainWeakReference?.get()?.getString(R.string.referer)!!,
mainWeakReference?.get()?.getString(R.string.pc_ua)!! mainWeakReference?.get()?.getString(R.string.pc_ua)!!

View File

@@ -1,16 +1,23 @@
package top.fumiama.copymanga.template.ui package top.fumiama.copymanga.template.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
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.Target
import kotlinx.android.synthetic.main.card_book.*
import kotlinx.android.synthetic.main.card_book.view.* import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.line_horizonal_empty.view.* import kotlinx.android.synthetic.main.line_horizonal_empty.view.*
import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.android.synthetic.main.line_lazybooklines.*
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -110,14 +117,22 @@ class CardList(
that?.context?.let { context -> that?.context?.let { context ->
Glide.with(context).load( Glide.with(context).load(
GlideUrl(CMApi.proxy?.wrap(head)?:head, CMApi.myGlideHeaders) GlideUrl(CMApi.proxy?.wrap(head)?:head, CMApi.myGlideHeaders)
).into(it.imic) ).addListener(GlideHideLottieViewListener(WeakReference(it.laic))).into(it.imic)
} }
} else { } else {
it.laic.pauseAnimation()
it.laic.visibility = View.GONE
it.imic.setImageResource(R.drawable.img_defmask) it.imic.setImageResource(R.drawable.img_defmask)
} }
} else { } else {
val img = File(file, "head.jpg") val img = File(file, "head.jpg")
if(img.exists()) it.imic.setImageURI(Uri.fromFile(img)) it.laic.pauseAnimation()
it.laic.visibility = View.GONE
if(img.exists()) {
it.imic.setImageURI(Uri.fromFile(img))
} else {
it.imic.setImageResource(R.drawable.img_defmask)
}
} }
if(card.isFinish) it.sgnic.visibility = View.VISIBLE if(card.isFinish) it.sgnic.visibility = View.VISIBLE
if(card.isNew) it.sgnnew.visibility = View.VISIBLE if(card.isNew) it.sgnnew.visibility = View.VISIBLE

View File

@@ -10,7 +10,7 @@ import top.fumiama.dmzj.copymanga.R
@ExperimentalStdlibApi @ExperimentalStdlibApi
open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) { open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) {
val sortWay = listOf("datetime_updated", "-datetime_updated", "popular", "-popular") val sortWay = listOf("-datetime_updated", "datetime_updated", "popular", "-popular")
var sortValue = 0 var sortValue = 0
override fun getApiUrl() = override fun getApiUrl() =

View File

@@ -3,11 +3,14 @@ package top.fumiama.copymanga.tools.http
import android.util.Log import android.util.Log
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.lang.Thread.sleep import java.lang.Thread.sleep
import java.util.zip.CRC32 import java.util.zip.CRC32
import java.util.zip.CheckedOutputStream import java.util.zip.CheckedOutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import kotlin.random.Random
class DownloadPool(folder: String) { class DownloadPool(folder: String) {
class Quest(val fileName: String, val imgUrl: Array<String>, val refer: String? = null) class Quest(val fileName: String, val imgUrl: Array<String>, val refer: String? = null)
@@ -22,9 +25,9 @@ class DownloadPool(folder: String) {
var wait = false var wait = false
private val saveFolder = File(folder) private val saveFolder = File(folder)
//fileName: String, isSuccess: Boolean //fileName: String, isSuccess: Boolean
private var mOnDownloadListener: ((String, Boolean) -> Unit)? = null private var mOnDownloadListener: ((String, Boolean, String) -> Unit)? = null
//fileName: String, downloaded: Int, total: Int, isSuccess: Boolean //fileName: String, downloaded: Int, total: Int, isSuccess: Boolean
private var mOnPageDownloadListener: ((String, Int, Int, Boolean) -> Unit)? = null private var mOnPageDownloadListener: ((String, Int, Int, Boolean, String) -> Unit)? = null
init { init {
if(!saveFolder.exists()) saveFolder.mkdirs() if(!saveFolder.exists()) saveFolder.mkdirs()
} }
@@ -37,50 +40,76 @@ class DownloadPool(folder: String) {
Thread{ Thread{
quests.forEach { quest -> quests.forEach { quest ->
packZipFile(quest.fileName, quest.imgUrl, quest.refer) packZipFile(quest.fileName, quest.imgUrl, quest.refer)
sleep(1000)
} }
}.start() }.start()
} }
fun setOnDownloadListener(onDownloadListener: (String, Boolean) -> Unit) { fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) {
mOnDownloadListener = onDownloadListener mOnDownloadListener = onDownloadListener
} }
fun setOnPageDownloadListener(onPageDownloadListener: (String, Int, Int, Boolean) -> Unit) { fun setOnPageDownloadListener(onPageDownloadListener: (String, Int, Int, Boolean, String) -> Unit) {
mOnPageDownloadListener = onPageDownloadListener mOnPageDownloadListener = onPageDownloadListener
} }
private fun packZipFile(fileName: String, imgUrls: Array<String>, refer: String?) { private fun packZipFile(fileName: String, imgUrls: Array<String>, refer: String?) {
Thread{ Thread{
File(saveFolder, fileName).let { f -> File(saveFolder, "$fileName.tmp").let { f ->
f.parentFile?.let { if(!it.exists()) it.mkdirs() } f.parentFile?.let { if(!it.exists()) it.mkdirs() }
if(f.exists()) f.delete() var start = 0
f.createNewFile()
Log.d("MyDP", "Zip file: ${f.absolutePath}") Log.d("MyDP", "Zip file: ${f.absolutePath}")
val zip = ZipOutputStream(CheckedOutputStream(f.outputStream(), CRC32())) if(f.exists()) {
try {
val zipFile = ZipFile(f)
start = zipFile.size() - 1
zipFile.close()
Log.d("MyDP", "last downloaded index: $start")
if (start <= 0 || start >= imgUrls.size) { // error or re-download
f.delete()
f.createNewFile()
start = 0
}
} catch (e: Exception) {
e.printStackTrace()
f.delete()
f.createNewFile()
}
} else f.createNewFile()
val zip = ZipOutputStream(CheckedOutputStream(FileOutputStream(f, true), CRC32()))
zip.setLevel(9) zip.setLevel(9)
var succeed = true var succeed = true
for(index in imgUrls.indices) { var lastIndex = -8
while (wait && !exit) sleep(1000) try {
for(index in start until imgUrls.size) {
while (wait && !exit) sleep(100+Random.nextLong(1000))
if(exit) break if(exit) break
zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}"))
var tryTimes = 3 var tryTimes = 3
var s = false var s = false
while (!s && tryTimes-- > 0) { while (!s && tryTimes-- > 0) {
val u = imgUrls[index] val u = imgUrls[index]
s = (DownloadTools.getHttpContent(CMApi.proxy?.wrap(u)?:u, -1))?.let { zip.write(it); true }?:false s = (DownloadTools.getHttpContent(CMApi.proxy?.wrap(u)?:u, -1))?.let {
zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}"))
zip.write(it)
zip.closeEntry()
true
}?:false
if (!s) sleep(2000) if (!s) sleep(2000)
} }
if(!s && tryTimes <= 0) { if(!s && tryTimes <= 0) {
succeed = false succeed = false
mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false) } mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false, "超过最大重试次数") }
break break
} else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true) } } else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true, "") }
//zip.flush() lastIndex = index
} }
zip.close() zip.close()
mOnPageDownloadListener?.let { it(fileName, 0, 0, true) } if (succeed && lastIndex+1 >= imgUrls.size) f.renameTo(File(saveFolder, fileName))
mOnDownloadListener?.let { it(fileName, succeed) } mOnPageDownloadListener?.let { it(fileName, 0, 0, true, "") }
mOnDownloadListener?.let { it(fileName, succeed, "") }
} catch (e: Exception) {
e.printStackTrace()
mOnDownloadListener?.let { it(fileName, false, e.localizedMessage?:"packZipFile") }
}
} }
}.start() }.start()
} }

View File

@@ -0,0 +1,35 @@
package top.fumiama.copymanga.tools.ui
import android.graphics.drawable.Drawable
import android.view.View
import com.airbnb.lottie.LottieAnimationView
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
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> {
override fun onLoadFailed(
e: GlideException?,
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 {
wla.get()?.apply {
pauseAnimation()
visibility = View.GONE
}
return false
}
}

View File

@@ -1,5 +1,6 @@
package top.fumiama.copymanga.tools.ui package top.fumiama.copymanga.tools.ui
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
@@ -42,6 +43,10 @@ class UITools(that: Context?, w: WeakReference<Activity>? = null) {
Toast.makeText(zis, s, Toast.LENGTH_SHORT).show() Toast.makeText(zis, s, Toast.LENGTH_SHORT).show()
if (willFinish) weak?.get()?.finish() if (willFinish) weak?.get()?.finish()
} }
fun toastError(s: Int, willFinish: Boolean = true) {
Toast.makeText(zis, s, Toast.LENGTH_SHORT).show()
if (willFinish) weak?.get()?.finish()
}
fun buildInfo( fun buildInfo(
title: String, title: String,
msg: String, msg: String,
@@ -84,7 +89,7 @@ class UITools(that: Context?, w: WeakReference<Activity>? = null) {
fun dp2px(dp:Int):Int?{ fun dp2px(dp:Int):Int?{
return zis?.resources?.displayMetrics?.density?.let { (dp * it + 0.5).toInt()} return zis?.resources?.displayMetrics?.density?.let { (dp * it + 0.5).toInt()}
} }
fun px2dp(px:Int):Int?{ private fun px2dp(px:Int):Int?{
return zis?.resources?.displayMetrics?.density?.let { (px.toDouble() / it + 0.5).toInt()} return zis?.resources?.displayMetrics?.density?.let { (px.toDouble() / it + 0.5).toInt()}
} }
fun calcWidthFromDp(marginLeftDp:Int, widthDp:Int):List<Int>{ fun calcWidthFromDp(marginLeftDp:Int, widthDp:Int):List<Int>{
@@ -124,22 +129,24 @@ class UITools(that: Context?, w: WeakReference<Activity>? = null) {
} }
toString() toString()
} }
@SuppressLint("DiscouragedApi", "InternalInsetResource")
fun getNavigationBarHeight(context: Context): Int { fun getNavigationBarHeight(context: Context): Int {
val resources = context.resources val resources = context.resources
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0) { return if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId) resources.getDimensionPixelSize(resourceId)
} else { } else {
0 64
} }
} }
@SuppressLint("DiscouragedApi", "InternalInsetResource")
fun getStatusBarHeight(context: Context): Int { fun getStatusBarHeight(context: Context): Int {
val resources = context.resources val resources = context.resources
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
return if (resourceId > 0) { return if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId) resources.getDimensionPixelSize(resourceId)
} else { } else {
0 64
} }
} }
} }

View File

@@ -26,6 +26,7 @@ import java.lang.ref.WeakReference
class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
var fbibinfo: View? = null var fbibinfo: View? = null
var fbtinfo: View? = null var fbtinfo: View? = null
var isOnPause = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@@ -67,14 +68,21 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
} }
} }
/*override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
mainWeakReference?.get()?.apply { isOnPause = false
/*mainWeakReference?.get()?.apply {
toolbar.title = bookHandler?.book?.results?.comic?.name toolbar.title = bookHandler?.book?.results?.comic?.name
} }
setStartRead() setStartRead()
fbibinfo?.layoutParams?.height = ((fbibinfo?.width?:0) * 4.0 / 9.0 + 0.5).toInt() fbibinfo?.layoutParams?.height = ((fbibinfo?.width?:0) * 4.0 / 9.0 + 0.5).toInt()
}*/ */
}
override fun onPause() {
super.onPause()
isOnPause = true
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()

View File

@@ -33,6 +33,7 @@ import top.fumiama.copymanga.template.http.AutoDownloadHandler
import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideBlurTransformation import top.fumiama.copymanga.tools.ui.GlideBlurTransformation
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.copymanga.tools.ui.Navigate import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json
@@ -147,7 +148,7 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
book?.results?.comic?.cover?.let { cover -> book?.results?.comic?.cover?.let { cover ->
val load = Glide.with(this).load( val load = Glide.with(this).load(
GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders) GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders)
).timeout(10000) ).timeout(10000).addListener(GlideHideLottieViewListener(WeakReference(laic)))
load.into(imic) load.into(imic)
context?.let { it1 -> GlideBlurTransformation(it1) } context?.let { it1 -> GlideBlurTransformation(it1) }
?.let { it2 -> RequestOptions.bitmapTransform(it2) } ?.let { it2 -> RequestOptions.bitmapTransform(it2) }
@@ -286,6 +287,10 @@ class BookHandler(private val th: WeakReference<BookFragment>, val path: String)
chapterNames += it.name chapterNames += it.name
ViewMangaActivity.uuidArray += it.uuid ViewMangaActivity.uuidArray += it.uuid
Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}") Log.d("MyBH", "i = $i, last=$last, add chapter ${it.name}, line is null: ${line == null}")
that?.isOnPause?.let { isOnPause ->
while (isOnPause && !exit) sleep(1000)
if (exit) return@Thread
}?:return@Thread
if(line == null) { if(line == null) {
if(i == last) { if(i == last) {
line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false) line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false)

View File

@@ -225,25 +225,27 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
return@setOnLongClickListener true return@setOnLongClickListener true
} }
mangaDlTools.onDownloadedListener = object :MangaDlTools.OnDownloadedListener{ mangaDlTools.onDownloadedListener = object :MangaDlTools.OnDownloadedListener{
override fun handleMessage(index: Int, isSuccess: Boolean) { override fun handleMessage(index: Int, isSuccess: Boolean, message: String) {
that?.activity?.runOnUiThread { that?.activity?.runOnUiThread {
if(isSuccess) onZipDownloadFinish(index) if(isSuccess) onZipDownloadFinish(index)
else onZipDownloadFailure(index) else onZipDownloadFailure(index, message)
} }
} }
@SuppressLint("SetTextI18n")
override fun handleMessage( override fun handleMessage(
index: Int, index: Int,
downloaded: Int, downloaded: Int,
total: Int, total: Int,
isSuccess: Boolean isSuccess: Boolean,
message: String
) { ) {
that?.activity?.runOnUiThread { that?.activity?.runOnUiThread {
if(isSuccess) { if(isSuccess) {
tbtnlist[index].text = if(downloaded == 0 && total == 0) tbtnlist[index].chapterName else "$downloaded/$total" tbtnlist[index].text = if(downloaded == 0 && total == 0) tbtnlist[index].chapterName else "$downloaded/$total"
} else { } else {
tbtnlist[index].text = "$downloaded/$total" tbtnlist[index].text = "$downloaded/$total"
Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}的第${downloaded}页失败", Toast.LENGTH_SHORT).show() Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}的第${downloaded}页失败: $message", Toast.LENGTH_SHORT).show()
} }
} }
} }
@@ -283,6 +285,7 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
updateProgressBar() updateProgressBar()
that?.apply { that?.apply {
cdwn.postDelayed({ cdwn.postDelayed({
if (mangaDlTools?.exit != false) return@postDelayed
if (dldChapter == checkedChapter) { if (dldChapter == checkedChapter) {
checkedChapter = 0 checkedChapter = 0
setProgress2(0, 233) setProgress2(0, 233)
@@ -296,9 +299,9 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference<ComicDlFragme
} }
} }
private fun onZipDownloadFailure(index: Int) { private fun onZipDownloadFailure(index: Int, message: String) {
tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error) tbtnlist[index].setBackgroundResource(R.drawable.rndbg_error)
Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败", Toast.LENGTH_SHORT).show() Toast.makeText(that?.context, "下载${tbtnlist[index].chapterName}失败: $message", Toast.LENGTH_SHORT).show()
updateProgressBar() updateProgressBar()
} }

View File

@@ -1,9 +1,14 @@
package top.fumiama.copymanga.ui.download package top.fumiama.copymanga.ui.download
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.provider.DocumentsContract
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
@@ -124,12 +129,12 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground) .setIcon(R.drawable.ic_launcher_foreground)
.setTitle(R.string.new_download_card_option_hint) .setTitle(R.string.new_download_card_option_hint)
.setItems(arrayOf("删除", "前往")) { d, p -> .setItems(arrayOf("删除数据", "前往详情")) { d, p ->
d.cancel() d.cancel()
when (p) { when (p) {
0 -> { 0 -> {
AlertDialog.Builder(context) AlertDialog.Builder(context)
.setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画吗?") .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画${name}吗?")
.setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ -> .setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ ->
if (chosenFile.exists()) Thread { if (chosenFile.exists()) Thread {
FileUtils.recursiveRemove(chosenFile) FileUtils.recursiveRemove(chosenFile)

View File

@@ -10,7 +10,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.ImageButton import android.widget.ImageButton
import androidx.appcompat.view.ContextThemeWrapper
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -29,8 +28,8 @@ import top.fumiama.copymanga.json.BookListStructure
import top.fumiama.copymanga.template.general.NoBackRefreshFragment import top.fumiama.copymanga.template.general.NoBackRefreshFragment
import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.copymanga.tools.ui.Navigate import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.dmzj.copymanga.R import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -72,13 +71,20 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
} }
}) })
setTextHint(android.R.string.search_go) setTextHint(android.R.string.search_go)
setOnQueryTextListener(object : SearchLayout.OnQueryTextListener { setOnQueryTextListener(object : SearchLayout.OnQueryTextListener {
var lastChangeTime = 0L var lastChangeTime = 0L
var lastSearch: String = ""
override fun onQueryTextChange(newText: CharSequence): Boolean { override fun onQueryTextChange(newText: CharSequence): Boolean {
if (newText.contentEquals("__notice_focus_change__") || newText.contentEquals(lastSearch)) return true
postDelayed({ postDelayed({
val diff = System.currentTimeMillis() - lastChangeTime val diff = System.currentTimeMillis() - lastChangeTime
if(diff > 500) { if(diff > 500) {
if (newText.isNotEmpty()) adapter.refresh(newText) if (newText.isNotEmpty()) {
Log.d("MyHF", "new text: $newText")
lastSearch = newText.toString()
adapter.refresh(newText)
}
} }
}, 1024) }, 1024)
lastChangeTime = System.currentTimeMillis() lastChangeTime = System.currentTimeMillis()
@@ -90,6 +96,8 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
val key = query.toString() val key = query.toString()
Toast.makeText(context, key, Toast.LENGTH_SHORT).show() Toast.makeText(context, key, Toast.LENGTH_SHORT).show()
}*/ }*/
Log.d("MyHF", "recover text: $lastSearch")
setTextQuery(lastSearch, false)
return true return true
} }
}) })
@@ -112,9 +120,12 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener { setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener {
override fun onFocusChange(hasFocus: Boolean) { override fun onFocusChange(hasFocus: Boolean) {
Log.d("MyHF", "fhs onFocusChange: $hasFocus") Log.d("MyHF", "fhs onFocusChange: $hasFocus")
navigationIconSupport = if (hasFocus) SearchLayout.NavigationIconSupport.ARROW navigationIconSupport = if (hasFocus) {
setTextQuery("__notice_focus_change__", true)
SearchLayout.NavigationIconSupport.ARROW
}
else { else {
micView.postDelayed({ micView.visibility = View.VISIBLE }, 233) micView.postDelayed({ micView?.visibility = View.VISIBLE }, 233)
SearchLayout.NavigationIconSupport.SEARCH SearchLayout.NavigationIconSupport.SEARCH
} }
} }
@@ -171,7 +182,7 @@ 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.proxy?.wrap(it)?:it, CMApi.myGlideHeaders) GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders)
).timeout(10000).into(holder.itemView.vpi) ).addListener(GlideHideLottieViewListener(WeakReference(holder.itemView.lai))).timeout(10000).into(holder.itemView.vpi)
} }
holder.itemView.vpt.text = thisBanner?.brief holder.itemView.vpt.text = thisBanner?.brief
holder.itemView.vpc.setOnClickListener { holder.itemView.vpc.setOnClickListener {
@@ -190,7 +201,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
RecyclerView.Adapter<ListViewHolder>() { RecyclerView.Adapter<ListViewHolder>() {
private var results: BookListStructure? = null private var results: BookListStructure? = null
var type = "" var type = ""
private var query: CharSequence? = null private var query: String? = null
private var count = 0 private var count = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
return ListViewHolder( return ListViewHolder(
@@ -228,7 +239,10 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
} }
holder.itemView.tb.text = popular.toString() holder.itemView.tb.text = popular.toString()
context?.let { context?.let {
Glide.with(it).load(GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders)).into(holder.itemView.imic) Glide.with(it)
.load(GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders))
.addListener(GlideHideLottieViewListener(WeakReference(holder.itemView.laic)))
.into(holder.itemView.imic)
} }
holder.itemView.lwc.setOnClickListener { holder.itemView.lwc.setOnClickListener {
val bundle = Bundle() val bundle = Bundle()
@@ -239,10 +253,10 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
} }
} }
override fun getItemCount() = (results?.results?.list?.size?:0)+1 override fun getItemCount() = (results?.results?.list?.size?:0) + if (query?.isNotEmpty() == true) 1 else 0
fun refresh(q: CharSequence) { fun refresh(q: CharSequence) {
query = q query = q.toString()
activity?.apply { activity?.apply {
AutoDownloadThread(getString(R.string.searchApiUrl).format(CMApi.myHostApiUrl, 0, query, type)) { AutoDownloadThread(getString(R.string.searchApiUrl).format(CMApi.myHostApiUrl, 0, query, type)) {
results = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java) results = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java)

View File

@@ -21,13 +21,14 @@ import com.to.aboomy.pager2banner.ScaleInTransformer
import kotlinx.android.synthetic.main.card_book.view.* import kotlinx.android.synthetic.main.card_book.view.*
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.line_1bookline.view.* import kotlinx.android.synthetic.main.line_1bookline.view.*
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.json.ComicStructure import top.fumiama.copymanga.json.ComicStructure
import top.fumiama.copymanga.json.IndexStructure import top.fumiama.copymanga.json.IndexStructure
import top.fumiama.copymanga.template.http.AutoDownloadHandler import top.fumiama.copymanga.template.http.AutoDownloadHandler
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener
import top.fumiama.copymanga.tools.ui.Navigate import top.fumiama.copymanga.tools.ui.Navigate
import top.fumiama.copymanga.tools.ui.UITools import top.fumiama.copymanga.tools.ui.UITools
import top.fumiama.dmzj.copymanga.R
import java.lang.Thread.sleep import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@@ -310,7 +311,9 @@ class HomeHandler(private val that: WeakReference<HomeFragment>) : AutoDownloadH
cv.tic.text = name cv.tic.text = name
homeF?.let { homeF?.let {
if(img.startsWith("http")) it.activity?.runOnUiThread { if(img.startsWith("http")) it.activity?.runOnUiThread {
Glide.with(it).load(GlideUrl(CMApi.proxy?.wrap(img)?:img, CMApi.myGlideHeaders)).timeout(20000).into(cv.imic) Glide.with(it).load(GlideUrl(CMApi.proxy?.wrap(img)?:img, CMApi.myGlideHeaders))
.addListener(GlideHideLottieViewListener(WeakReference(cv.laic)))
.timeout(20000).into(cv.imic)
} }
} }
if (isFinal) cv.sgnic.visibility = View.VISIBLE if (isFinal) cv.sgnic.visibility = View.VISIBLE

View File

@@ -4,12 +4,15 @@ import android.widget.Toast
import top.fumiama.copymanga.manga.Reader import top.fumiama.copymanga.manga.Reader
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position
import top.fumiama.dmzj.copymanga.R
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class PagesManager(private val w: WeakReference<ViewMangaActivity>) { class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
val v get() = w.get() val v get() = w.get()
private var isEndL = false private var isEndL = false
private var isEndR = false private var isEndR = false
private val canGoPrevious get() = (v?.pageNum ?: 0) > 1
private val canGoNext get() = (v?.pageNum ?: 0) < (v?.realCount ?: 0)
@ExperimentalStdlibApi @ExperimentalStdlibApi
fun toPreviousPage(){ fun toPreviousPage(){
toPage(v?.r2l==true) toPage(v?.r2l==true)
@@ -18,16 +21,14 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
fun toNextPage(){ fun toNextPage(){
toPage(v?.r2l!=true) toPage(v?.r2l!=true)
} }
private fun judgePrevious() = (v?.pageNum ?: 0) > 1
private fun judgeNext() = (v?.pageNum ?: 0) < (v?.realCount ?: 0)
@ExperimentalStdlibApi @ExperimentalStdlibApi
fun toPage(goNext:Boolean) { fun toPage(goNext:Boolean) {
v?.let { v -> v?.let { v ->
if (v.clicked) { if (v.clicked) {
v.hideObjs() v.hideDrawer()
return return
} }
if (if(goNext)judgeNext() else judgePrevious()) { if (if(goNext) canGoNext else canGoPrevious) {
if(goNext) { if(goNext) {
v.scrollForward() v.scrollForward()
isEndR = false isEndR = false
@@ -38,33 +39,26 @@ class PagesManager(private val w: WeakReference<ViewMangaActivity>) {
return return
} }
val chapterPosition = position + if(goNext) 1 else -1 val chapterPosition = position + if(goNext) 1 else -1
if (v.urlArray.isNotEmpty()) { if (v.urlArray.isEmpty()) return
if(chapterPosition >= 0 && chapterPosition < v.urlArray.size) v.urlArray[chapterPosition].let { if(chapterPosition < 0 || chapterPosition >= v.urlArray.size) {
Toast.makeText(v.applicationContext, R.string.end_of_chapter, Toast.LENGTH_SHORT).show()
return
}
if (if(goNext) isEndR else isEndL) { if (if(goNext) isEndR else isEndL) {
//if(v.zipFirst) intent.putExtra("callFrom", "zipFirst") //if(v.zipFirst) intent.putExtra("callFrom", "zipFirst")
v.tt.canDo = false v.tt.canDo = false
//ViewMangaActivity.dlhandler = null //ViewMangaActivity.dlhandler = null
comicName?.let { it1 -> Reader.viewMangaAt(it1, chapterPosition, v.urlArray, goNext) } comicName?.let { Reader.viewMangaAt(it, chapterPosition, v.urlArray, goNext) }
v.finish() v.finish()
return return
} }
val hint = if(goNext) '下' else '上' val hint = if(goNext) R.string.press_again_to_load_next_chapter else R.string.press_again_to_load_previous_chapter
Toast.makeText( Toast.makeText(v.applicationContext, hint, Toast.LENGTH_SHORT).show()
v.applicationContext,
"再次按下加载${hint}一章",
Toast.LENGTH_SHORT
).show()
if(goNext) isEndR = true if(goNext) isEndR = true
else isEndL = true else isEndL = true
} else Toast.makeText(
v.applicationContext,
"已经到头了~",
Toast.LENGTH_SHORT
).show()
} }
} }
} fun toggleDrawer() {
fun manageInfo(){ if (v?.clicked == false) v?.showDrawer() else v?.hideDrawer()
if (v?.clicked == false) v?.showObjs() else v?.hideObjs()
} }
} }

View File

@@ -7,11 +7,11 @@ import android.os.Looper
import android.os.Message import android.os.Message
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_viewmanga.* import kotlinx.android.synthetic.main.activity_viewmanga.*
import kotlinx.android.synthetic.main.widget_infodrawer.* import kotlinx.android.synthetic.main.widget_infodrawer.*
import kotlinx.android.synthetic.main.widget_infodrawer.view.* import kotlinx.android.synthetic.main.widget_infodrawer.view.*
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.json.Chapter2Return import top.fumiama.copymanga.json.Chapter2Return
import top.fumiama.copymanga.json.ChapterWithContent import top.fumiama.copymanga.json.ChapterWithContent
import top.fumiama.copymanga.json.ComicStructure import top.fumiama.copymanga.json.ComicStructure
@@ -21,21 +21,20 @@ import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.pn
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position
import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.uuidArray import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.uuidArray
import top.fumiama.copymanga.views.ScaleImageView import top.fumiama.copymanga.views.ScaleImageView
import top.fumiama.dmzj.copymanga.R
import java.io.File import java.io.File
import java.lang.Exception
import java.lang.Thread.sleep
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicInteger
class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
url, Chapter2Return::class.java, Looper.myLooper()!! url, Chapter2Return::class.java, Looper.myLooper()!!
) { ) {
var manga: Chapter2Return? = null var manga: Chapter2Return? = null
private val wv = WeakReference(activity) private val wv = WeakReference(activity)
private val infcard = wv.get()?.infcard private val drawer = wv.get()?.infcard
private var infcShowed = false private val weeks = wv.get()?.getStringArray(R.array.weeks)
private var hasDrawerShown = false
val dl = activity.let { val dl = activity.let {
val re = Dialog(it) val re = Dialog(it)
re.setContentView(R.layout.dialog_unzipping) re.setContentView(R.layout.dialog_unzipping)
@@ -49,16 +48,9 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
private val week: String private val week: String
get() { get() {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
return when (cal[Calendar.DAY_OF_WEEK]) { val w = cal[Calendar.DAY_OF_WEEK]
1 -> "周日" if (w > 7 || w <= 0) return ""
2 -> "周一" return weeks?.get(w-1) ?: ""
3 -> "周二"
4 -> "周三"
5 -> "周四"
6 -> "周五"
7 -> "周六"
else -> ""
}
} }
private var remainingImageCount = 0 private var remainingImageCount = 0
@@ -66,21 +58,22 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
super.handleMessage(msg) super.handleMessage(msg)
when (msg.what) { when (msg.what) {
HIDE_INFO_CARD -> if (infcShowed) { HIDE_INFO_CARD -> if (hasDrawerShown) {
hideInfCard(); infcShowed = false hideInfCard(); hasDrawerShown = false
} }
SHOW_INFO_CARD -> if (!infcShowed) { SHOW_INFO_CARD -> if (!hasDrawerShown) {
showInfCard(); infcShowed = true showInfCard(); hasDrawerShown = true
} }
TRIGGER_INFO_CARD -> infcShowed = if (infcShowed) { TRIGGER_INFO_CARD -> hasDrawerShown = if (hasDrawerShown) {
hideInfCard(); false hideInfCard(); false
} else { } else {
showInfCard(); true showInfCard(); true
} }
LOAD_IMG_ON -> { LOAD_IMG_ON -> {
val simg = msg.obj as ScaleImageView val scaleImageView = msg.obj as ScaleImageView
wv.get()?.loadImgOn(simg, msg.arg1, msg.arg2) // msg.arg2: isLast
//simg.setHeight2FitImgWidth() wv.get()?.loadImgOn(scaleImageView, msg.arg1)
//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 -> {
@@ -106,13 +99,13 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
Log.d("MyVMH", "Load page from $item") Log.d("MyVMH", "Load page from $item")
} }
DIALOG_HIDE -> dl.hide() DIALOG_HIDE -> dl.hide()
HIDE_INFO_CARD_FULL -> if (infcShowed) { HIDE_INFO_CARD_FULL -> if (hasDrawerShown) {
hideInfCardFull(); infcShowed = false hideInfCardFull(); hasDrawerShown = false
} }
SHOW_INFO_CARD_FULL -> if (!infcShowed) { SHOW_INFO_CARD_FULL -> if (!hasDrawerShown) {
showInfCardFull(); infcShowed = true showInfCardFull(); hasDrawerShown = true
} }
TRIGGER_INFO_CARD_FULL -> infcShowed = if (infcShowed) { TRIGGER_INFO_CARD_FULL -> hasDrawerShown = if (hasDrawerShown) {
hideInfCardFull(); false hideInfCardFull(); false
} else { } else {
showInfCardFull(); true showInfCardFull(); true
@@ -147,7 +140,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
override fun onError() { override fun onError() {
super.onError() super.onError()
if(exit) return if(exit) return
wv.get()?.toolsBox?.toastError("下载章节信息失败") wv.get()?.toolsBox?.toastError(R.string.download_chapter_info_failed)
} }
override fun doWhenFinishDownload() { override fun doWhenFinishDownload() {
@@ -181,7 +174,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
true true
} catch (e: Exception){ } catch (e: Exception){
e.printStackTrace() e.printStackTrace()
//wv.get()?.toolsBox?.toastError("读取本地章节信息失败") wv.get()?.toolsBox?.toastError(R.string.load_local_chapter_info_failed)
false false
} }
} }
@@ -225,23 +218,23 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler(
private fun showInfCard() { private fun showInfCard() {
Log.d("MyVMH", "Read info drawer delta: $delta") Log.d("MyVMH", "Read info drawer delta: $delta")
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.3F, 0.8F).setDuration(233).start() ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.3F, 0.8F).setDuration(233).start()
ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start() ObjectAnimator.ofFloat(drawer, "translationY", delta, 0F).setDuration(233).start()
} }
private fun showInfCardFull() { private fun showInfCardFull() {
Log.d("MyVMH", "Read info drawer delta: $delta") Log.d("MyVMH", "Read info drawer delta: $delta")
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.0F, 0.8F).setDuration(233).start() ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.0F, 0.8F).setDuration(233).start()
ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start() ObjectAnimator.ofFloat(drawer, "translationY", delta, 0F).setDuration(233).start()
} }
private fun hideInfCard() { private fun hideInfCard() {
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.8F, 0.3F).setDuration(233).start() ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.8F, 0.3F).setDuration(233).start()
ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start() ObjectAnimator.ofFloat(drawer, "translationY", 0F, delta).setDuration(233).start()
} }
private fun hideInfCardFull() { private fun hideInfCardFull() {
ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.8F, 0.0F).setDuration(233).start() ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.8F, 0.0F).setDuration(233).start()
ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start() ObjectAnimator.ofFloat(drawer, "translationY", 0F, delta).setDuration(233).start()
} }
companion object { companion object {

View File

@@ -8,6 +8,7 @@ import android.graphics.BitmapFactory
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.media.AudioManager import android.media.AudioManager
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@@ -20,10 +21,9 @@ import androidx.core.content.edit
import androidx.preference.PreferenceManager 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.afollestad.materialdialogs.utils.MDUtil.getStringArray
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.target.CustomTarget
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.*
@@ -36,14 +36,14 @@ 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 top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.MainActivity
import top.fumiama.dmzj.copymanga.R
import top.fumiama.copymanga.template.general.TitleActivityTemplate import top.fumiama.copymanga.template.general.TitleActivityTemplate
import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.template.http.AutoDownloadThread
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.ui.Font
import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.http.DownloadTools
import top.fumiama.copymanga.tools.thread.TimeThread import top.fumiama.copymanga.tools.thread.TimeThread
import top.fumiama.copymanga.tools.ui.Font
import top.fumiama.copymanga.views.ScaleImageView import top.fumiama.copymanga.views.ScaleImageView
import top.fumiama.dmzj.copymanga.R
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
@@ -51,6 +51,7 @@ import java.io.InputStream
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.concurrent.FutureTask import java.util.concurrent.FutureTask
import java.util.zip.ZipFile import java.util.zip.ZipFile
import kotlin.math.abs
class ViewMangaActivity : TitleActivityTemplate() { class ViewMangaActivity : TitleActivityTemplate() {
var count = 0 var count = 0
@@ -69,6 +70,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
private var notUseVP = true private var notUseVP = true
private var isVertical = false private var isVertical = false
private var q = 100 private var q = 100
private var tryWebpFirst = true
private val size get() = if(realCount / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else realCount % verticalLoadMaxCount private val size get() = if(realCount / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else realCount % verticalLoadMaxCount
var infoDrawerDelta = 0f var infoDrawerDelta = 0f
var pageNum: Int var pageNum: Int
@@ -130,10 +132,11 @@ class ViewMangaActivity : TitleActivityTemplate() {
} else prepareImgFromWeb() } else prepareImgFromWeb()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
toolsBox.toastError("加载漫画错误") toolsBox.toastError(R.string.load_manga_error)
} }
} }
@Suppress("DEPRECATION")
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus) super.onWindowFocusChanged(hasFocus)
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R) if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R)
@@ -144,7 +147,6 @@ class ViewMangaActivity : TitleActivityTemplate() {
hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars()) hide(WindowInsets.Type.statusBars() or WindowInsets.Type.navigationBars())
systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} }
} }
} }
@@ -183,7 +185,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
private fun preDownloadChapterPages() { private fun preDownloadChapterPages() {
getImgUrlArray()?.let { getImgUrlArray()?.let {
val mid = (if(pn in 1 until realCount) (if(cut) Math.abs(indexMap[pn]) else pn) else if(pn == -2 || pn >= realCount) it.size else 1) - 1 val 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 left = if(isVertical && mid > verticalLoadMaxCount) (mid / verticalLoadMaxCount) * verticalLoadMaxCount else (mid-1)
val right = if(isVertical) (mid / verticalLoadMaxCount + 1) * verticalLoadMaxCount else mid val right = if(isVertical) (mid / verticalLoadMaxCount + 1) * verticalLoadMaxCount else mid
tasks = arrayOfNulls(it.size) tasks = arrayOfNulls(it.size)
@@ -277,7 +279,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
fun countZipEntries(doWhenFinish : (count: Int) -> Unit) = Thread{ fun countZipEntries(doWhenFinish : (count: Int) -> Unit) = Thread{
if (zipFile != null) try { if (zipFile != null) try {
Log.d("Myvm", "zip: $zipFile") Log.d("MyVM", "zip: $zipFile")
val zip = ZipFile(zipFile) val zip = ZipFile(zipFile)
count = zip.size() count = zip.size()
if(cut) zip.entries().toList().sortedBy{it.name.substringBefore('.').toInt()}.forEachIndexed { i, it -> if(cut) zip.entries().toList().sortedBy{it.name.substringBefore('.').toInt()}.forEachIndexed { i, it ->
@@ -285,13 +287,13 @@ class ViewMangaActivity : TitleActivityTemplate() {
isCut += useCut isCut += useCut
indexMap += i + 1 indexMap += i + 1
if (useCut) indexMap += -(i + 1) if (useCut) indexMap += -(i + 1)
Log.d("Myvm", "[$i] 分析: ${it.name}, cut: $useCut") Log.d("MyVM", "[$i] 分析: ${it.name}, cut: $useCut")
} }
} catch (e: Exception) { } catch (e: Exception) {
runOnUiThread { toolsBox.toastError("统计zip图片数错误!") } runOnUiThread { toolsBox.toastError(R.string.count_zip_entries_error) }
} }
runOnUiThread { runOnUiThread {
Log.d("Myvm", "开始加载控件") Log.d("MyVM", "开始加载控件")
doWhenFinish(count) doWhenFinish(count)
} }
}.start() }.start()
@@ -318,7 +320,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
loadOneImg() loadOneImg()
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
toolsBox.toastError("页数${currentItem}不合法") toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem))
} }
} }
} else { } else {
@@ -364,22 +366,21 @@ class ViewMangaActivity : TitleActivityTemplate() {
private fun cutBitmap(bitmap: Bitmap, isEnd: Boolean) = Bitmap.createBitmap(bitmap, if(!isEnd) 0 else (bitmap.width/2), 0, bitmap.width/2, bitmap.height) private fun cutBitmap(bitmap: Bitmap, isEnd: Boolean) = Bitmap.createBitmap(bitmap, if(!isEnd) 0 else (bitmap.width/2), 0, bitmap.width/2, bitmap.height)
private fun loadImg(imgView: ScaleImageView, bitmap: Bitmap, isLast: Int = 0, useCut: Boolean, isLeft: Boolean, isPlaceholder: Boolean = true) { private fun loadImg(imgView: ScaleImageView, bitmap: Bitmap, useCut: Boolean, isLeft: Boolean, isPlaceholder: Boolean = true) {
val bitmap2load = if(!isPlaceholder && useCut) cutBitmap(bitmap, isLeft) else bitmap val bitmap2load = if(!isPlaceholder && useCut) cutBitmap(bitmap, isLeft) else bitmap
runOnUiThread { runOnUiThread {
imgView.setImageBitmap(bitmap2load) imgView.setImageBitmap(bitmap2load)
if(!isPlaceholder && isVertical) { if(!isPlaceholder && isVertical) {
imgView.setHeight2FitImgWidth() imgView.setHeight2FitImgWidth()
handler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO) handler.sendEmptyMessage(VMHandler.DECREASE_IMAGE_COUNT_AND_RESTORE_PAGE_NUMBER_AT_ZERO)
//if (!isPlaceholder && isLast == 1) handler.sendEmptyMessageDelayed(VMHandler.RESTORE_PAGE_NUMBER, 233)
} }
} }
} }
private fun loadImgUrlInto(imgView: ScaleImageView, url: String, isLast: Int = 0, useCut: Boolean, isLeft: Boolean){ private fun loadImgUrlInto(imgView: ScaleImageView, url: String, useCut: Boolean, isLeft: Boolean){
Log.d("MyVM", "Load from adt: $url") Log.d("MyVM", "Load from adt: $url")
AutoDownloadThread(CMApi.proxy?.wrap(url)?:url) { AutoDownloadThread(CMApi.proxy?.wrap(url)?:url, 1000) {
it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), isLast, useCut, isLeft, false) } it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) }
}.start() }.start()
} }
@@ -397,28 +398,28 @@ class ViewMangaActivity : TitleActivityTemplate() {
return loading return loading
} }
fun loadImgOn(imgView: ScaleImageView, position: Int, isLast: Int = 0){ fun loadImgOn(imgView: ScaleImageView, position: Int){
Log.d("MyVM", "Load img: $position") Log.d("MyVM", "Load img: $position")
val index2load = if(cut) Math.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 { if (zipFile?.exists() == true) getImgBitmap(index2load)?.let {
loadImg(imgView, it, isLast, useCut, isLeft, false) loadImg(imgView, it, useCut, isLeft, false)
} }
else { else {
loadImg(imgView, getLoadingBitmap(position), isLast, useCut, isLeft, true) loadImg(imgView, getLoadingBitmap(position), useCut, isLeft, true)
val re = tasks?.get(index2load) val re = tasks?.get(index2load)
if (re != null) Thread{ if (re != null) Thread{
val data = re.get() val data = re.get()
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, isLast, 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")
} }
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, isLast, useCut, isLeft) } else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
}.start() }.start()
else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, isLast, useCut, isLeft) } else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) }
} }
imgView.visibility = View.VISIBLE imgView.visibility = View.VISIBLE
} }
@@ -445,28 +446,30 @@ class ViewMangaActivity : TitleActivityTemplate() {
if (position >= count || position < 0) null if (position >= count || position < 0) null
else { else {
val zip = ZipFile(zipFile) val zip = ZipFile(zipFile)
try { var bitmap: Bitmap? = null
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp"))) for (i in 0..1) {
val ext = if((i == 0 && tryWebpFirst) || (i == 1 && !tryWebpFirst)) "webp" else "jpg"
bitmap = try {
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.$ext")))
else { else {
val out = ByteArrayOutputStream() val out = ByteArrayOutputStream()
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.$ext")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
}
} catch (e: Exception) {
try {
if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))
else {
val out = ByteArrayOutputStream()
BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))?.compress(Bitmap.CompressFormat.JPEG, q, out)
BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray())) BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray()))
} }
} catch (e: Exception) { } catch (e: Exception) {
if (i == 1) {
e.printStackTrace() e.printStackTrace()
Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show() Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show()
}
null null
} }
if (bitmap != null) {
tryWebpFirst = ext == "webp"
break
} }
} }
bitmap
}
private fun setIdPosition(position: Int) { private fun setIdPosition(position: Int) {
infoDrawerDelta = position.toFloat() infoDrawerDelta = position.toFloat()
@@ -493,7 +496,8 @@ class ViewMangaActivity : TitleActivityTemplate() {
}*/ }*/
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
toolsBox.toastError("准备控件错误") toolsBox.toastError(R.string.load_chapter_error)
finish()
} }
} }
@@ -512,7 +516,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
idtbcut.isChecked = cut idtbcut.isChecked = cut
idtbcut.setOnClickListener { idtbcut.setOnClickListener {
pb["useCut"] = idtbcut.isChecked pb["useCut"] = idtbcut.isChecked
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
} }
} }
@@ -520,7 +524,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
idtblr.isChecked = r2l idtblr.isChecked = r2l
idtblr.setOnClickListener { idtblr.setOnClickListener {
pb["r2l"] = idtblr.isChecked pb["r2l"] = idtblr.isChecked
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
} }
} }
@@ -528,7 +532,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
idtbvp.isChecked = notUseVP idtbvp.isChecked = notUseVP
idtbvp.setOnClickListener { idtbvp.setOnClickListener {
pb["noVP"] = idtbvp.isChecked pb["noVP"] = idtbvp.isChecked
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
} }
} }
@@ -551,7 +555,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
fun updateSeekBar() { fun updateSeekBar() {
if (!isInSeek) hideObjs() if (!isInSeek) hideDrawer()
updateSeekText() updateSeekText()
updateSeekProgress() updateSeekProgress()
setProgress() setProgress()
@@ -591,21 +595,22 @@ class ViewMangaActivity : TitleActivityTemplate() {
idtbvh.isChecked = isVertical idtbvh.isChecked = isVertical
pm = PagesManager(WeakReference(this)) pm = PagesManager(WeakReference(this))
if (isVertical) { if (isVertical) {
val vsps = vsp as SpringView (vsp as SpringView).apply {
vsps.footerView.lht.text = "更多" footerView.lht.setText(R.string.button_more)
vsps.headerView.lht.text = "更多" headerView.lht.setText(R.string.button_more)
vsps.setListener(object :SpringView.OnFreshListener{ setListener(object :SpringView.OnFreshListener{
override fun onLoadmore() { override fun onLoadmore() {
//scrollForward() //scrollForward()
pm?.toPage(true) pm?.toPage(true)
vsps.onFinishFreshAndLoad() onFinishFreshAndLoad()
} }
override fun onRefresh() { override fun onRefresh() {
//scrollBack() //scrollBack()
pm?.toPage(false) pm?.toPage(false)
vsps.onFinishFreshAndLoad() onFinishFreshAndLoad()
} }
}) })
}
vp.visibility = View.GONE vp.visibility = View.GONE
vsp.visibility = View.VISIBLE vsp.visibility = View.VISIBLE
initImgList() initImgList()
@@ -623,7 +628,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
idtbvh.setOnClickListener { idtbvh.setOnClickListener {
pb["vertical"] = idtbvh.isChecked pb["vertical"] = idtbvh.isChecked
Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show()
} }
} }
@@ -674,7 +679,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
@SuppressLint("ClickableViewAccessibility", "SetTextI18n") @SuppressLint("ClickableViewAccessibility", "SetTextI18n")
override fun onBindViewHolder(holder: ViewData, position: Int) { override fun onBindViewHolder(holder: ViewData, position: Int) {
val pos = if (r2l) realCount - position - 1 else position val pos = if (r2l) realCount - position - 1 else position
val index2load = if(cut) Math.abs(indexMap[pos]) -1 else pos val index2load = if(cut) abs(indexMap[pos]) -1 else pos
val useCut = cut && isCut[index2load] val useCut = cut && isCut[index2load]
val isLeft = cut && indexMap[pos] > 0 val isLeft = cut && indexMap[pos] > 0
if (zipFile?.exists() == true) getImgBitmap(index2load)?.let { if (zipFile?.exists() == true) getImgBitmap(index2load)?.let {
@@ -684,15 +689,17 @@ class ViewMangaActivity : TitleActivityTemplate() {
else getImgUrl(index2load)?.let{ else getImgUrl(index2load)?.let{
if(useCut){ if(useCut){
val thisOneI = holder.itemView.onei val thisOneI = holder.itemView.onei
Glide.with(this@ViewMangaActivity) Glide.with(this@ViewMangaActivity.applicationContext)
.asBitmap() .asBitmap()
.load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders)) .load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders))
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.into(object : SimpleTarget<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))
} }) }
} else Glide.with(this@ViewMangaActivity) override fun onLoadCleared(placeholder: Drawable?) { }
})
} else Glide.with(this@ViewMangaActivity.applicationContext)
.load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders)) .load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders))
.placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos)))
.into(holder.itemView.onei) .into(holder.itemView.onei)
@@ -705,7 +712,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
} }
} }
fun showObjs() { fun showDrawer() {
infseek.visibility = View.VISIBLE infseek.visibility = View.VISIBLE
isearch.visibility = View.VISIBLE isearch.visibility = View.VISIBLE
ObjectAnimator.ofFloat( ObjectAnimator.ofFloat(
@@ -717,7 +724,7 @@ class ViewMangaActivity : TitleActivityTemplate() {
clicked = true clicked = true
} }
fun hideObjs() { fun hideDrawer() {
ObjectAnimator.ofFloat( ObjectAnimator.ofFloat(
oneinfo, oneinfo,
"alpha", "alpha",

View File

@@ -1,12 +1,9 @@
package top.fumiama.copymanga.user package top.fumiama.copymanga.user
import android.content.SharedPreferences import android.content.SharedPreferences
import android.widget.Toast
import com.google.gson.Gson import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import top.fumiama.copymanga.MainActivity
import top.fumiama.copymanga.json.LoginInfoStructure import top.fumiama.copymanga.json.LoginInfoStructure
import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.api.CMApi
import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.http.DownloadTools
@@ -47,6 +44,12 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) -
fun refreshAvatar() : LoginInfoStructure { fun refreshAvatar() : LoginInfoStructure {
if (!pref.contains("token")) {
val l = LoginInfoStructure()
l.code = 400
l.message = getString(R.string.noLogin)
return l
}
try { try {
DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format( DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format(
CMApi.myHostApiUrl))?.decodeToString()?.let { CMApi.myHostApiUrl))?.decodeToString()?.let {

View File

@@ -16,6 +16,7 @@ import android.view.MotionEvent
import android.widget.ImageView import android.widget.ImageView
import top.fumiama.copymanga.ui.vm.PagesManager import top.fumiama.copymanga.ui.vm.PagesManager
import top.fumiama.copymanga.ui.vm.ViewMangaActivity import top.fumiama.copymanga.ui.vm.ViewMangaActivity
import top.fumiama.dmzj.copymanga.R
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
import kotlin.math.sqrt import kotlin.math.sqrt
@@ -563,7 +564,7 @@ class ScaleImageView : ImageView {
} }
}catch (e:Exception){ }catch (e:Exception){
e.printStackTrace() e.printStackTrace()
ViewMangaActivity.va?.get()?.toolsBox?.toastError("图片加载错误,请尝试下载后使用较低图片质量查看", false) ViewMangaActivity.va?.get()?.toolsBox?.toastError(R.string.show_image_error_try_lower_resolution, false)
} }
} }
////////////////////////////////有效性判断//////////////////////////////// ////////////////////////////////有效性判断////////////////////////////////
@@ -688,7 +689,7 @@ class ScaleImageView : ImageView {
(event.x / width).let { (event.x / width).let {
when { when {
it <= 1.0 / 3.0 -> pm?.toPreviousPage() it <= 1.0 / 3.0 -> pm?.toPreviousPage()
it <= 2.0 / 3.0 -> pm?.manageInfo() it <= 2.0 / 3.0 -> pm?.toggleDrawer()
else -> pm?.toNextPage() else -> pm?.toNextPage()
} }
} }

View File

@@ -16,16 +16,13 @@
android:id="@+id/coordiv" android:id="@+id/coordiv"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="16dp" android:layout_height="16dp"
android:background="?attr/colorPrimarySurface" android:background="?attr/colorPrimarySurface" />
android:visibility="visible"
app:layout_scrollFlags="scroll|enterAlways" />
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimarySurface" android:background="?attr/colorPrimarySurface"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay" /> app:popupTheme="@style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

View File

@@ -37,6 +37,19 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/laic"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lottie_loading" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -36,6 +36,19 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/laic"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lottie_loading" />
<include <include
android:id="@+id/sgnic" android:id="@+id/sgnic"
layout="@layout/widget_finalmark" layout="@layout/widget_finalmark"

View File

@@ -26,6 +26,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/lai"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="@raw/lottie_loading" />
<ImageView <ImageView
android:id="@+id/vpi" android:id="@+id/vpi"
android:layout_width="0dp" android:layout_width="0dp"

File diff suppressed because one or more lines are too long

View File

@@ -4,6 +4,8 @@
]> ]>
<resources> <resources>
<string name="app_name">拷贝漫画</string> <string name="app_name">拷贝漫画</string>
<string name="file_provider_authority">top.fumiama.copymanga.fileprovider</string>
<string name="action_settings">设定</string> <string name="action_settings">设定</string>
<string name="action_info">关于</string> <string name="action_info">关于</string>
<string name="action_download">下载</string> <string name="action_download">下载</string>
@@ -40,6 +42,17 @@
<string name="web_error">网络错误</string> <string name="web_error">网络错误</string>
<string name="download_cover_failed">保存封面失败</string> <string name="download_cover_failed">保存封面失败</string>
<string name="download_cover_timeout">保存封面超时</string> <string name="download_cover_timeout">保存封面超时</string>
<string name="take_effect_on_reload">下次浏览生效</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>
<string name="load_local_chapter_info_failed">读取本地章节信息失败</string>
<string name="download_chapter_info_failed">下载章节信息失败</string>
<string name="load_manga_error">加载漫画错误</string>
<string name="count_zip_entries_error">统计zip图片数错误</string>
<string name="load_page_number_error">第%1$d页加载异常</string>
<string name="load_chapter_error">加载章节错误</string>
<string name="show_image_error_try_lower_resolution">图片加载错误,请尝试下载后使用较低图片质量查看</string>
<string name="mainPageApiUrl">https://%1$s/api/v3/h5/homeIndex?platform=3</string> <string name="mainPageApiUrl">https://%1$s/api/v3/h5/homeIndex?platform=3</string>
<string name="referUrl">https://%1$s</string> <string name="referUrl">https://%1$s</string>
@@ -153,4 +166,5 @@
<string name="old_download_card_name">前往旧版下载</string> <string name="old_download_card_name">前往旧版下载</string>
<string name="new_download_card_option_hint">选择您的操作</string> <string name="new_download_card_option_hint">选择您的操作</string>
<string name="choose_how_download_folder">选择如何打开漫画下载目录</string>
</resources> </resources>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="weeks">
<item>周日</item>
<item>周一</item>
<item>周二</item>
<item>周三</item>
<item>周四</item>
<item>周五</item>
<item>周六</item>
</string-array>
</resources>

View File

@@ -23,4 +23,3 @@ android.enableR8.fullMode=true
android.defaults.buildfeatures.buildconfig=true android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false android.nonTransitiveRClass=false
android.nonFinalResIds=false android.nonFinalResIds=false
org.gradle.unsafe.configuration-cache=true