diff --git a/.idea/dictionaries/fumiama.xml b/.idea/dictionaries/fumiama.xml index 58e02df..b79f8e3 100644 --- a/.idea/dictionaries/fumiama.xml +++ b/.idea/dictionaries/fumiama.xml @@ -1,6 +1,7 @@ + imgs lowpan nisi diff --git a/app/build.gradle b/app/build.gradle index 631eb83..6745300 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId 'top.fumiama.copymanga' minSdkVersion 23 targetSdkVersion 34 - versionCode 41 - versionName '2.0.5' + versionCode 42 + versionName '2.0.6' resConfigs 'zh', 'zh-rCN' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -58,10 +58,10 @@ dependencies { implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' 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.navigation:navigation-fragment-ktx:2.7.5' - implementation 'androidx.navigation:navigation-ui-ktx:2.7.5' + implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6' + implementation 'androidx.navigation:navigation-ui-ktx:2.7.6' testImplementation 'junit:junit:4.13.2' implementation "androidx.preference:preference-ktx:1.2.1" implementation 'com.afollestad.material-dialogs:input:3.3.0' @@ -74,5 +74,6 @@ dependencies { implementation 'com.liaoinstan.springview:library:1.7.0' implementation 'com.github.zawadz88.materialpopupmenu:material-popup-menu:4.0.1' 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' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 60d3dfe..c0d6801 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ android:usesCleartextTraffic="true"> - Gson().fromJson(data?.decodeToString(), Chapter2Return::class.java)?.let { - getChapterInfo(it, index, chapterName, group) + AutoDownloadThread(url.toString(), 1000) { data -> + try { + Gson().fromJson(data?.decodeToString(), Chapter2Return::class.java)?.let { + getChapterInfo(it, index, chapterName, group) + } + } catch (e: Exception) { + e.printStackTrace() + onDownloadedListener?.handleMessage(index, false, e.localizedMessage?:"Gson parsing error") } }.start() } @Synchronized private fun prepareDownloadListener() { - pool?.setOnDownloadListener { fileName: String, isSuccess: Boolean -> - indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, isSuccess) } + pool?.setOnDownloadListener { fileName: String, isSuccess: Boolean, message: String -> + indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, isSuccess, message) } } - pool?.setOnPageDownloadListener { fileName: String, downloaded: Int, total: Int, isSuccess: Boolean -> - indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, downloaded, total, isSuccess) } + pool?.setOnPageDownloadListener { fileName: String, downloaded: Int, total: Int, isSuccess: Boolean, message: String -> + indexMap[fileName]?.let { onDownloadedListener?.handleMessage(it, downloaded, total, isSuccess, message) } } } @@ -83,7 +88,7 @@ class MangaDlTools { var onDownloadedListener: OnDownloadedListener? = null interface OnDownloadedListener{ - fun handleMessage(index: Int, isSuccess: Boolean) - fun handleMessage(index: Int, downloaded: Int, total: Int, isSuccess: Boolean) + fun handleMessage(index: Int, isSuccess: Boolean, message: String) + fun handleMessage(index: Int, downloaded: Int, total: Int, isSuccess: Boolean, message: String) } } diff --git a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt index 27f21b6..1137c35 100644 --- a/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt +++ b/app/src/main/java/top/fumiama/copymanga/template/http/AutoDownloadThread.kt @@ -4,14 +4,16 @@ import android.util.Log import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference import top.fumiama.copymanga.tools.http.DownloadTools 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 override fun run() { super.run() var re: ByteArray? = null 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, mainWeakReference?.get()?.getString(R.string.referer)!!, mainWeakReference?.get()?.getString(R.string.pc_ua)!! diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt index df7f53a..6906c92 100644 --- a/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt +++ b/app/src/main/java/top/fumiama/copymanga/template/ui/CardList.kt @@ -1,16 +1,23 @@ 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.* import kotlinx.android.synthetic.main.line_lazybooklines.* import top.fumiama.copymanga.tools.api.CMApi +import top.fumiama.copymanga.tools.ui.GlideHideLottieViewListener import top.fumiama.dmzj.copymanga.R import java.io.File import java.lang.ref.WeakReference @@ -110,14 +117,22 @@ class CardList( that?.context?.let { context -> Glide.with(context).load( GlideUrl(CMApi.proxy?.wrap(head)?:head, CMApi.myGlideHeaders) - ).into(it.imic) + ).addListener(GlideHideLottieViewListener(WeakReference(it.laic))).into(it.imic) } } else { + it.laic.pauseAnimation() + it.laic.visibility = View.GONE it.imic.setImageResource(R.drawable.img_defmask) } } else { 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.isNew) it.sgnnew.visibility = View.VISIBLE diff --git a/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt b/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt index 6b0eae2..f66b858 100644 --- a/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt +++ b/app/src/main/java/top/fumiama/copymanga/template/ui/StatusCardFlow.kt @@ -10,7 +10,7 @@ import top.fumiama.dmzj.copymanga.R @ExperimentalStdlibApi open class StatusCardFlow(private val api: Int, nav: Int) : InfoCardLoader(R.layout.fragment_statuscardflow, nav) { - val sortWay = listOf("datetime_updated", "-datetime_updated", "popular", "-popular") + val sortWay = listOf("-datetime_updated", "datetime_updated", "popular", "-popular") var sortValue = 0 override fun getApiUrl() = diff --git a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt index 244c04c..3fefe6c 100644 --- a/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt +++ b/app/src/main/java/top/fumiama/copymanga/tools/http/DownloadPool.kt @@ -3,11 +3,14 @@ package top.fumiama.copymanga.tools.http import android.util.Log import top.fumiama.copymanga.tools.api.CMApi import java.io.File +import java.io.FileOutputStream import java.lang.Thread.sleep import java.util.zip.CRC32 import java.util.zip.CheckedOutputStream import java.util.zip.ZipEntry +import java.util.zip.ZipFile import java.util.zip.ZipOutputStream +import kotlin.random.Random class DownloadPool(folder: String) { class Quest(val fileName: String, val imgUrl: Array, val refer: String? = null) @@ -22,9 +25,9 @@ class DownloadPool(folder: String) { var wait = false private val saveFolder = File(folder) //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 - private var mOnPageDownloadListener: ((String, Int, Int, Boolean) -> Unit)? = null + private var mOnPageDownloadListener: ((String, Int, Int, Boolean, String) -> Unit)? = null init { if(!saveFolder.exists()) saveFolder.mkdirs() } @@ -37,50 +40,76 @@ class DownloadPool(folder: String) { Thread{ quests.forEach { quest -> packZipFile(quest.fileName, quest.imgUrl, quest.refer) - sleep(1000) } }.start() } - fun setOnDownloadListener(onDownloadListener: (String, Boolean) -> Unit) { + fun setOnDownloadListener(onDownloadListener: (String, Boolean, String) -> Unit) { mOnDownloadListener = onDownloadListener } - fun setOnPageDownloadListener(onPageDownloadListener: (String, Int, Int, Boolean) -> Unit) { + fun setOnPageDownloadListener(onPageDownloadListener: (String, Int, Int, Boolean, String) -> Unit) { mOnPageDownloadListener = onPageDownloadListener } private fun packZipFile(fileName: String, imgUrls: Array, refer: String?) { Thread{ - File(saveFolder, fileName).let { f -> + File(saveFolder, "$fileName.tmp").let { f -> f.parentFile?.let { if(!it.exists()) it.mkdirs() } - if(f.exists()) f.delete() - f.createNewFile() + var start = 0 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) var succeed = true - for(index in imgUrls.indices) { - while (wait && !exit) sleep(1000) - if(exit) break - zip.putNextEntry(ZipEntry("$index.${if(imgUrls[index].contains(".webp")) "webp" else "jpg"}")) - var tryTimes = 3 - var s = false - while (!s && tryTimes-- > 0){ - val u = imgUrls[index] - s = (DownloadTools.getHttpContent(CMApi.proxy?.wrap(u)?:u, -1))?.let { zip.write(it); true }?:false - if (!s) sleep(2000) + var lastIndex = -8 + try { + for(index in start until imgUrls.size) { + while (wait && !exit) sleep(100+Random.nextLong(1000)) + if(exit) break + var tryTimes = 3 + var s = false + while (!s && tryTimes-- > 0) { + val u = imgUrls[index] + 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 && tryTimes <= 0) { + succeed = false + mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false, "超过最大重试次数") } + break + } else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true, "") } + lastIndex = index } - if(!s && tryTimes <= 0) { - succeed = false - mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, false) } - break - } else mOnPageDownloadListener?.let { it(fileName, index + 1, imgUrls.size, true) } - //zip.flush() + zip.close() + if (succeed && lastIndex+1 >= imgUrls.size) f.renameTo(File(saveFolder, fileName)) + 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") } } - zip.close() - mOnPageDownloadListener?.let { it(fileName, 0, 0, true) } - mOnDownloadListener?.let { it(fileName, succeed) } } }.start() } diff --git a/app/src/main/java/top/fumiama/copymanga/tools/ui/GlideHideLottieViewListener.kt b/app/src/main/java/top/fumiama/copymanga/tools/ui/GlideHideLottieViewListener.kt new file mode 100644 index 0000000..0dea257 --- /dev/null +++ b/app/src/main/java/top/fumiama/copymanga/tools/ui/GlideHideLottieViewListener.kt @@ -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): RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + return false + } + + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + wla.get()?.apply { + pauseAnimation() + visibility = View.GONE + } + return false + } +} \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt b/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt index d3e96b9..4d9eec4 100644 --- a/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt +++ b/app/src/main/java/top/fumiama/copymanga/tools/ui/UITools.kt @@ -1,5 +1,6 @@ package top.fumiama.copymanga.tools.ui +import android.annotation.SuppressLint import android.app.Activity import android.app.AlertDialog import android.content.Context @@ -42,6 +43,10 @@ class UITools(that: Context?, w: WeakReference? = null) { Toast.makeText(zis, s, Toast.LENGTH_SHORT).show() 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( title: String, msg: String, @@ -84,7 +89,7 @@ class UITools(that: Context?, w: WeakReference? = null) { fun dp2px(dp:Int):Int?{ 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()} } fun calcWidthFromDp(marginLeftDp:Int, widthDp:Int):List{ @@ -124,22 +129,24 @@ class UITools(that: Context?, w: WeakReference? = null) { } toString() } + @SuppressLint("DiscouragedApi", "InternalInsetResource") fun getNavigationBarHeight(context: Context): Int { val resources = context.resources val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") return if (resourceId > 0) { resources.getDimensionPixelSize(resourceId) } else { - 0 + 64 } } + @SuppressLint("DiscouragedApi", "InternalInsetResource") fun getStatusBarHeight(context: Context): Int { val resources = context.resources val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") return if (resourceId > 0) { resources.getDimensionPixelSize(resourceId) } else { - 0 + 64 } } } diff --git a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt index 46e669d..7e561f8 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookFragment.kt @@ -26,6 +26,7 @@ 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?) { super.onViewCreated(view, savedInstanceState) @@ -67,14 +68,21 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { } } - /*override fun onResume() { + override fun onResume() { super.onResume() - mainWeakReference?.get()?.apply { + isOnPause = false + /*mainWeakReference?.get()?.apply { toolbar.title = bookHandler?.book?.results?.comic?.name } setStartRead() fbibinfo?.layoutParams?.height = ((fbibinfo?.width?:0) * 4.0 / 9.0 + 0.5).toInt() - }*/ + */ + } + + override fun onPause() { + super.onPause() + isOnPause = true + } override fun onDestroy() { super.onDestroy() diff --git a/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt index 2628ed5..b4539e5 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/book/BookHandler.kt @@ -33,6 +33,7 @@ import top.fumiama.copymanga.template.http.AutoDownloadHandler import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.tools.api.CMApi 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.ui.comicdl.ComicDlFragment import top.fumiama.copymanga.ui.comicdl.ComicDlFragment.Companion.json @@ -147,7 +148,7 @@ class BookHandler(private val th: WeakReference, val path: String) book?.results?.comic?.cover?.let { cover -> val load = Glide.with(this).load( GlideUrl(CMApi.proxy?.wrap(cover)?:cover, CMApi.myGlideHeaders) - ).timeout(10000) + ).timeout(10000).addListener(GlideHideLottieViewListener(WeakReference(laic))) load.into(imic) context?.let { it1 -> GlideBlurTransformation(it1) } ?.let { it2 -> RequestOptions.bitmapTransform(it2) } @@ -286,6 +287,10 @@ class BookHandler(private val th: WeakReference, val path: String) chapterNames += it.name ViewMangaActivity.uuidArray += it.uuid 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(i == last) { line = layoutInflater.inflate(R.layout.line_chapter, that!!.fbl, false) diff --git a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt index f700775..4651a0c 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/comicdl/ComicDlHandler.kt @@ -225,25 +225,27 @@ class ComicDlHandler(looper: Looper, private val th: WeakReference + .setItems(arrayOf("删除数据", "前往详情")) { d, p -> d.cancel() when (p) { 0 -> { AlertDialog.Builder(context) - .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的此漫画吗?") + .setIcon(R.drawable.ic_launcher_foreground).setMessage("删除下载的漫画${name}吗?") .setTitle("提示").setPositiveButton(android.R.string.ok) { _, _ -> if (chosenFile.exists()) Thread { FileUtils.recursiveRemove(chosenFile) diff --git a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt index ebcb20a..521b94f 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeFragment.kt @@ -10,7 +10,6 @@ import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.ImageButton -import androidx.appcompat.view.ContextThemeWrapper import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager 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.http.AutoDownloadThread 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.UITools import top.fumiama.dmzj.copymanga.R import java.lang.Thread.sleep import java.lang.ref.WeakReference @@ -72,13 +71,20 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { } }) setTextHint(android.R.string.search_go) + setOnQueryTextListener(object : SearchLayout.OnQueryTextListener { var lastChangeTime = 0L + var lastSearch: String = "" override fun onQueryTextChange(newText: CharSequence): Boolean { + if (newText.contentEquals("__notice_focus_change__") || newText.contentEquals(lastSearch)) return true postDelayed({ val diff = System.currentTimeMillis() - lastChangeTime 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) lastChangeTime = System.currentTimeMillis() @@ -90,6 +96,8 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { val key = query.toString() Toast.makeText(context, key, Toast.LENGTH_SHORT).show() }*/ + Log.d("MyHF", "recover text: $lastSearch") + setTextQuery(lastSearch, false) return true } }) @@ -112,9 +120,12 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { setOnFocusChangeListener(object : SearchLayout.OnFocusChangeListener { override fun onFocusChange(hasFocus: Boolean) { Log.d("MyHF", "fhs onFocusChange: $hasFocus") - navigationIconSupport = if (hasFocus) SearchLayout.NavigationIconSupport.ARROW + navigationIconSupport = if (hasFocus) { + setTextQuery("__notice_focus_change__", true) + SearchLayout.NavigationIconSupport.ARROW + } else { - micView.postDelayed({ micView.visibility = View.VISIBLE }, 233) + micView.postDelayed({ micView?.visibility = View.VISIBLE }, 233) SearchLayout.NavigationIconSupport.SEARCH } } @@ -171,7 +182,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { //Log.d("MyHomeFVP", "Load img: $it") Glide.with(this@HomeFragment).load( 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.vpc.setOnClickListener { @@ -190,7 +201,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { RecyclerView.Adapter() { private var results: BookListStructure? = null var type = "" - private var query: CharSequence? = null + private var query: String? = null private var count = 0 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder { return ListViewHolder( @@ -228,7 +239,10 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { } holder.itemView.tb.text = popular.toString() 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 { 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) { - query = q + query = q.toString() activity?.apply { AutoDownloadThread(getString(R.string.searchApiUrl).format(CMApi.myHostApiUrl, 0, query, type)) { results = Gson().fromJson(it?.decodeToString(), BookListStructure::class.java) diff --git a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt index eefb20a..7d88c0e 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/home/HomeHandler.kt @@ -21,13 +21,14 @@ import com.to.aboomy.pager2banner.ScaleInTransformer import kotlinx.android.synthetic.main.card_book.view.* import kotlinx.android.synthetic.main.fragment_home.* 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.IndexStructure import top.fumiama.copymanga.template.http.AutoDownloadHandler 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.UITools +import top.fumiama.dmzj.copymanga.R import java.lang.Thread.sleep import java.lang.ref.WeakReference @@ -310,7 +311,9 @@ class HomeHandler(private val that: WeakReference) : AutoDownloadH cv.tic.text = name homeF?.let { 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 diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt index ad54c14..cabf244 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/PagesManager.kt @@ -4,12 +4,15 @@ import android.widget.Toast import top.fumiama.copymanga.manga.Reader import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.comicName import top.fumiama.copymanga.ui.vm.ViewMangaActivity.Companion.position +import top.fumiama.dmzj.copymanga.R import java.lang.ref.WeakReference class PagesManager(private val w: WeakReference) { val v get() = w.get() private var isEndL = false private var isEndR = false + private val canGoPrevious get() = (v?.pageNum ?: 0) > 1 + private val canGoNext get() = (v?.pageNum ?: 0) < (v?.realCount ?: 0) @ExperimentalStdlibApi fun toPreviousPage(){ toPage(v?.r2l==true) @@ -18,16 +21,14 @@ class PagesManager(private val w: WeakReference) { fun toNextPage(){ toPage(v?.r2l!=true) } - private fun judgePrevious() = (v?.pageNum ?: 0) > 1 - private fun judgeNext() = (v?.pageNum ?: 0) < (v?.realCount ?: 0) @ExperimentalStdlibApi fun toPage(goNext:Boolean) { v?.let { v -> if (v.clicked) { - v.hideObjs() + v.hideDrawer() return } - if (if(goNext)judgeNext() else judgePrevious()) { + if (if(goNext) canGoNext else canGoPrevious) { if(goNext) { v.scrollForward() isEndR = false @@ -38,33 +39,26 @@ class PagesManager(private val w: WeakReference) { return } val chapterPosition = position + if(goNext) 1 else -1 - if (v.urlArray.isNotEmpty()) { - if(chapterPosition >= 0 && chapterPosition < v.urlArray.size) v.urlArray[chapterPosition].let { - if (if(goNext) isEndR else isEndL) { - //if(v.zipFirst) intent.putExtra("callFrom", "zipFirst") - v.tt.canDo = false - //ViewMangaActivity.dlhandler = null - comicName?.let { it1 -> Reader.viewMangaAt(it1, chapterPosition, v.urlArray, goNext) } - v.finish() - return - } - val hint = if(goNext) '下' else '上' - Toast.makeText( - v.applicationContext, - "再次按下加载${hint}一章", - Toast.LENGTH_SHORT - ).show() - if(goNext) isEndR = true - else isEndL = true - } else Toast.makeText( - v.applicationContext, - "已经到头了~", - Toast.LENGTH_SHORT - ).show() + if (v.urlArray.isEmpty()) return + 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(v.zipFirst) intent.putExtra("callFrom", "zipFirst") + v.tt.canDo = false + //ViewMangaActivity.dlhandler = null + comicName?.let { Reader.viewMangaAt(it, chapterPosition, v.urlArray, goNext) } + v.finish() + return + } + val hint = if(goNext) R.string.press_again_to_load_next_chapter else R.string.press_again_to_load_previous_chapter + Toast.makeText(v.applicationContext, hint, Toast.LENGTH_SHORT).show() + if(goNext) isEndR = true + else isEndL = true } } - fun manageInfo(){ - if (v?.clicked == false) v?.showObjs() else v?.hideObjs() + fun toggleDrawer() { + if (v?.clicked == false) v?.showDrawer() else v?.hideDrawer() } } diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt index 3b2fffb..83e2674 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/VMHandler.kt @@ -7,11 +7,11 @@ import android.os.Looper import android.os.Message import android.util.Log import android.view.View +import com.afollestad.materialdialogs.utils.MDUtil.getStringArray import com.google.gson.Gson import kotlinx.android.synthetic.main.activity_viewmanga.* import kotlinx.android.synthetic.main.widget_infodrawer.* 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.ChapterWithContent 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.uuidArray import top.fumiama.copymanga.views.ScaleImageView +import top.fumiama.dmzj.copymanga.R import java.io.File -import java.lang.Exception -import java.lang.Thread.sleep import java.lang.ref.WeakReference import java.text.SimpleDateFormat import java.util.* -import java.util.concurrent.atomic.AtomicInteger class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( url, Chapter2Return::class.java, Looper.myLooper()!! ) { var manga: Chapter2Return? = null private val wv = WeakReference(activity) - private val infcard = wv.get()?.infcard - private var infcShowed = false + private val drawer = wv.get()?.infcard + private val weeks = wv.get()?.getStringArray(R.array.weeks) + private var hasDrawerShown = false val dl = activity.let { val re = Dialog(it) re.setContentView(R.layout.dialog_unzipping) @@ -49,16 +48,9 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( private val week: String get() { val cal = Calendar.getInstance() - return when (cal[Calendar.DAY_OF_WEEK]) { - 1 -> "周日" - 2 -> "周一" - 3 -> "周二" - 4 -> "周三" - 5 -> "周四" - 6 -> "周五" - 7 -> "周六" - else -> "" - } + val w = cal[Calendar.DAY_OF_WEEK] + if (w > 7 || w <= 0) return "" + return weeks?.get(w-1) ?: "" } private var remainingImageCount = 0 @@ -66,21 +58,22 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { - HIDE_INFO_CARD -> if (infcShowed) { - hideInfCard(); infcShowed = false + HIDE_INFO_CARD -> if (hasDrawerShown) { + hideInfCard(); hasDrawerShown = false } - SHOW_INFO_CARD -> if (!infcShowed) { - showInfCard(); infcShowed = true + SHOW_INFO_CARD -> if (!hasDrawerShown) { + showInfCard(); hasDrawerShown = true } - TRIGGER_INFO_CARD -> infcShowed = if (infcShowed) { + TRIGGER_INFO_CARD -> hasDrawerShown = if (hasDrawerShown) { hideInfCard(); false } else { showInfCard(); true } LOAD_IMG_ON -> { - val simg = msg.obj as ScaleImageView - wv.get()?.loadImgOn(simg, msg.arg1, msg.arg2) - //simg.setHeight2FitImgWidth() + val scaleImageView = msg.obj as ScaleImageView + // msg.arg2: isLast + wv.get()?.loadImgOn(scaleImageView, msg.arg1) + //scaleImageView.setHeight2FitImgWidth() //if(msg.arg2 == 1) sendEmptyMessage(DELAYED_RESTORE_PAGE_NUMBER) } CLEAR_IMG_ON -> { @@ -106,13 +99,13 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( Log.d("MyVMH", "Load page from $item") } DIALOG_HIDE -> dl.hide() - HIDE_INFO_CARD_FULL -> if (infcShowed) { - hideInfCardFull(); infcShowed = false + HIDE_INFO_CARD_FULL -> if (hasDrawerShown) { + hideInfCardFull(); hasDrawerShown = false } - SHOW_INFO_CARD_FULL -> if (!infcShowed) { - showInfCardFull(); infcShowed = true + SHOW_INFO_CARD_FULL -> if (!hasDrawerShown) { + showInfCardFull(); hasDrawerShown = true } - TRIGGER_INFO_CARD_FULL -> infcShowed = if (infcShowed) { + TRIGGER_INFO_CARD_FULL -> hasDrawerShown = if (hasDrawerShown) { hideInfCardFull(); false } else { showInfCardFull(); true @@ -147,7 +140,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( override fun onError() { super.onError() if(exit) return - wv.get()?.toolsBox?.toastError("下载章节信息失败") + wv.get()?.toolsBox?.toastError(R.string.download_chapter_info_failed) } override fun doWhenFinishDownload() { @@ -181,7 +174,7 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( true } catch (e: Exception){ e.printStackTrace() - //wv.get()?.toolsBox?.toastError("读取本地章节信息失败") + wv.get()?.toolsBox?.toastError(R.string.load_local_chapter_info_failed) false } } @@ -225,23 +218,23 @@ class VMHandler(activity: ViewMangaActivity, url: String) : AutoDownloadHandler( private fun showInfCard() { Log.d("MyVMH", "Read info drawer delta: $delta") - ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.3F, 0.8F).setDuration(233).start() - ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.3F, 0.8F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer, "translationY", delta, 0F).setDuration(233).start() } private fun showInfCardFull() { Log.d("MyVMH", "Read info drawer delta: $delta") - ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.0F, 0.8F).setDuration(233).start() - ObjectAnimator.ofFloat(infcard, "translationY", delta, 0F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.0F, 0.8F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer, "translationY", delta, 0F).setDuration(233).start() } private fun hideInfCard() { - ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.8F, 0.3F).setDuration(233).start() - ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start() + ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.8F, 0.3F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer, "translationY", 0F, delta).setDuration(233).start() } private fun hideInfCardFull() { - ObjectAnimator.ofFloat(infcard?.idc, "alpha", 0.8F, 0.0F).setDuration(233).start() - ObjectAnimator.ofFloat(infcard, "translationY", 0F, delta).setDuration(233).start() + ObjectAnimator.ofFloat(drawer?.idc, "alpha", 0.8F, 0.0F).setDuration(233).start() + ObjectAnimator.ofFloat(drawer, "translationY", 0F, delta).setDuration(233).start() } companion object { diff --git a/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt b/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt index c98cbf7..7b9854d 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/vm/ViewMangaActivity.kt @@ -8,6 +8,7 @@ import android.graphics.BitmapFactory import android.graphics.Canvas import android.graphics.Paint import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable import android.media.AudioManager import android.os.Bundle import android.os.Handler @@ -20,10 +21,9 @@ import androidx.core.content.edit import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 -import com.afollestad.materialdialogs.utils.MDUtil.getStringArray import com.bumptech.glide.Glide 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.liaoinstan.springview.widget.SpringView 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_viewmangainfo.* import top.fumiama.copymanga.MainActivity -import top.fumiama.dmzj.copymanga.R import top.fumiama.copymanga.template.general.TitleActivityTemplate import top.fumiama.copymanga.template.http.AutoDownloadThread import top.fumiama.copymanga.tools.api.CMApi -import top.fumiama.copymanga.tools.ui.Font import top.fumiama.copymanga.tools.http.DownloadTools import top.fumiama.copymanga.tools.thread.TimeThread +import top.fumiama.copymanga.tools.ui.Font import top.fumiama.copymanga.views.ScaleImageView +import top.fumiama.dmzj.copymanga.R import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File @@ -51,6 +51,7 @@ import java.io.InputStream import java.lang.ref.WeakReference import java.util.concurrent.FutureTask import java.util.zip.ZipFile +import kotlin.math.abs class ViewMangaActivity : TitleActivityTemplate() { var count = 0 @@ -69,6 +70,7 @@ class ViewMangaActivity : TitleActivityTemplate() { private var notUseVP = true private var isVertical = false private var q = 100 + private var tryWebpFirst = true private val size get() = if(realCount / verticalLoadMaxCount > currentItem / verticalLoadMaxCount) verticalLoadMaxCount else realCount % verticalLoadMaxCount var infoDrawerDelta = 0f var pageNum: Int @@ -130,10 +132,11 @@ class ViewMangaActivity : TitleActivityTemplate() { } else prepareImgFromWeb() } catch (e: Exception) { e.printStackTrace() - toolsBox.toastError("加载漫画错误") + toolsBox.toastError(R.string.load_manga_error) } } + @Suppress("DEPRECATION") override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) 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()) systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } - } } @@ -183,7 +185,7 @@ class ViewMangaActivity : TitleActivityTemplate() { private fun preDownloadChapterPages() { getImgUrlArray()?.let { - val mid = (if(pn in 1 until realCount) (if(cut) Math.abs(indexMap[pn]) else pn) else if(pn == -2 || pn >= realCount) it.size else 1) - 1 + val 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) @@ -277,7 +279,7 @@ class ViewMangaActivity : TitleActivityTemplate() { fun countZipEntries(doWhenFinish : (count: Int) -> Unit) = Thread{ if (zipFile != null) try { - Log.d("Myvm", "zip: $zipFile") + Log.d("MyVM", "zip: $zipFile") val zip = ZipFile(zipFile) count = zip.size() if(cut) zip.entries().toList().sortedBy{it.name.substringBefore('.').toInt()}.forEachIndexed { i, it -> @@ -285,13 +287,13 @@ class ViewMangaActivity : TitleActivityTemplate() { isCut += 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) { - runOnUiThread { toolsBox.toastError("统计zip图片数错误!") } + runOnUiThread { toolsBox.toastError(R.string.count_zip_entries_error) } } runOnUiThread { - Log.d("Myvm", "开始加载控件") + Log.d("MyVM", "开始加载控件") doWhenFinish(count) } }.start() @@ -318,7 +320,7 @@ class ViewMangaActivity : TitleActivityTemplate() { loadOneImg() } catch (e: Exception) { e.printStackTrace() - toolsBox.toastError("页数${currentItem}不合法") + toolsBox.toastError(getString(R.string.load_page_number_error).format(currentItem)) } } } 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 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 runOnUiThread { imgView.setImageBitmap(bitmap2load) if(!isPlaceholder && isVertical) { imgView.setHeight2FitImgWidth() 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") - AutoDownloadThread(CMApi.proxy?.wrap(url)?:url) { - it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), isLast, useCut, isLeft, false) } + AutoDownloadThread(CMApi.proxy?.wrap(url)?:url, 1000) { + it?.let { loadImg(imgView, BitmapFactory.decodeByteArray(it, 0, it.size), useCut, isLeft, false) } }.start() } @@ -397,28 +398,28 @@ class ViewMangaActivity : TitleActivityTemplate() { return loading } - fun loadImgOn(imgView: ScaleImageView, position: Int, isLast: Int = 0){ + fun loadImgOn(imgView: ScaleImageView, position: Int){ 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 isLeft = cut && indexMap[position] > 0 if (zipFile?.exists() == true) getImgBitmap(index2load)?.let { - loadImg(imgView, it, isLast, useCut, isLeft, false) + loadImg(imgView, it, useCut, isLeft, false) } else { - loadImg(imgView, getLoadingBitmap(position), isLast, useCut, isLeft, true) + 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, isLast, useCut, isLeft, false) + loadImg(imgView, it, useCut, isLeft, false) Log.d("MyVM", "Load position $position from task") }?: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() - else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, isLast, useCut, isLeft) } + else getImgUrl(index2load)?.let { loadImgUrlInto(imgView, it, useCut, isLeft) } } imgView.visibility = View.VISIBLE } @@ -445,27 +446,29 @@ class ViewMangaActivity : TitleActivityTemplate() { if (position >= count || position < 0) null else { val zip = ZipFile(zipFile) - try { - if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp"))) - else { - val out = ByteArrayOutputStream() - BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.webp")))?.compress(Bitmap.CompressFormat.JPEG, q, out) - BitmapFactory.decodeStream(ByteArrayInputStream(out.toByteArray())) - } - } catch (e: Exception) { - try { - if (q == 100) BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg"))) + var bitmap: Bitmap? = null + 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 { val out = ByteArrayOutputStream() - BitmapFactory.decodeStream(zip.getInputStream(zip.getEntry("${position}.jpg")))?.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) { - e.printStackTrace() - Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show() + if (i == 1) { + e.printStackTrace() + Toast.makeText(this, "加载zip的第${position}项错误", Toast.LENGTH_SHORT).show() + } null } + if (bitmap != null) { + tryWebpFirst = ext == "webp" + break + } } + bitmap } private fun setIdPosition(position: Int) { @@ -491,9 +494,10 @@ class ViewMangaActivity : TitleActivityTemplate() { it["chapterId"] = hm.chapterId.toString() it["name"] = inftitle.ttitle.text }*/ - }catch (e: Exception) { + } catch (e: Exception) { e.printStackTrace() - toolsBox.toastError("准备控件错误") + toolsBox.toastError(R.string.load_chapter_error) + finish() } } @@ -512,7 +516,7 @@ class ViewMangaActivity : TitleActivityTemplate() { idtbcut.isChecked = cut idtbcut.setOnClickListener { 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.setOnClickListener { 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.setOnClickListener { 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() { - if (!isInSeek) hideObjs() + if (!isInSeek) hideDrawer() updateSeekText() updateSeekProgress() setProgress() @@ -591,21 +595,22 @@ class ViewMangaActivity : TitleActivityTemplate() { idtbvh.isChecked = isVertical pm = PagesManager(WeakReference(this)) if (isVertical) { - val vsps = vsp as SpringView - vsps.footerView.lht.text = "更多" - vsps.headerView.lht.text = "更多" - vsps.setListener(object :SpringView.OnFreshListener{ - override fun onLoadmore() { - //scrollForward() - pm?.toPage(true) - vsps.onFinishFreshAndLoad() - } - override fun onRefresh() { - //scrollBack() - pm?.toPage(false) - vsps.onFinishFreshAndLoad() - } - }) + (vsp as SpringView).apply { + footerView.lht.setText(R.string.button_more) + headerView.lht.setText(R.string.button_more) + setListener(object :SpringView.OnFreshListener{ + override fun onLoadmore() { + //scrollForward() + pm?.toPage(true) + onFinishFreshAndLoad() + } + override fun onRefresh() { + //scrollBack() + pm?.toPage(false) + onFinishFreshAndLoad() + } + }) + } vp.visibility = View.GONE vsp.visibility = View.VISIBLE initImgList() @@ -623,7 +628,7 @@ class ViewMangaActivity : TitleActivityTemplate() { } idtbvh.setOnClickListener { pb["vertical"] = idtbvh.isChecked - Toast.makeText(this, "下次浏览生效", Toast.LENGTH_SHORT).show() + Toast.makeText(this, R.string.take_effect_on_reload, Toast.LENGTH_SHORT).show() } } @@ -633,7 +638,7 @@ class ViewMangaActivity : TitleActivityTemplate() { 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) - }else pageNum-- + } else pageNum-- } fun scrollForward() { @@ -674,7 +679,7 @@ class ViewMangaActivity : TitleActivityTemplate() { @SuppressLint("ClickableViewAccessibility", "SetTextI18n") override fun onBindViewHolder(holder: ViewData, position: Int) { 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 isLeft = cut && indexMap[pos] > 0 if (zipFile?.exists() == true) getImgBitmap(index2load)?.let { @@ -684,15 +689,17 @@ class ViewMangaActivity : TitleActivityTemplate() { else getImgUrl(index2load)?.let{ if(useCut){ val thisOneI = holder.itemView.onei - Glide.with(this@ViewMangaActivity) + Glide.with(this@ViewMangaActivity.applicationContext) .asBitmap() .load(GlideUrl(CMApi.proxy?.wrap(it)?:it, CMApi.myGlideHeaders)) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) - .into(object : SimpleTarget() { + .into(object : CustomTarget() { override fun onResourceReady(resource: Bitmap, transition: Transition?) { 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)) .placeholder(BitmapDrawable(resources, getLoadingBitmap(pos))) .into(holder.itemView.onei) @@ -705,7 +712,7 @@ class ViewMangaActivity : TitleActivityTemplate() { } } - fun showObjs() { + fun showDrawer() { infseek.visibility = View.VISIBLE isearch.visibility = View.VISIBLE ObjectAnimator.ofFloat( @@ -717,7 +724,7 @@ class ViewMangaActivity : TitleActivityTemplate() { clicked = true } - fun hideObjs() { + fun hideDrawer() { ObjectAnimator.ofFloat( oneinfo, "alpha", diff --git a/app/src/main/java/top/fumiama/copymanga/user/Member.kt b/app/src/main/java/top/fumiama/copymanga/user/Member.kt index 39f12da..c958b7a 100644 --- a/app/src/main/java/top/fumiama/copymanga/user/Member.kt +++ b/app/src/main/java/top/fumiama/copymanga/user/Member.kt @@ -1,12 +1,9 @@ package top.fumiama.copymanga.user import android.content.SharedPreferences -import android.widget.Toast import com.google.gson.Gson import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext -import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.json.LoginInfoStructure import top.fumiama.copymanga.tools.api.CMApi import top.fumiama.copymanga.tools.http.DownloadTools @@ -47,6 +44,12 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) - fun refreshAvatar() : LoginInfoStructure { + if (!pref.contains("token")) { + val l = LoginInfoStructure() + l.code = 400 + l.message = getString(R.string.noLogin) + return l + } try { DownloadTools.getHttpContent(getString(R.string.memberInfoApiUrl).format( CMApi.myHostApiUrl))?.decodeToString()?.let { @@ -65,7 +68,7 @@ class Member(private val pref: SharedPreferences, private val getString: (Int) - } val l = LoginInfoStructure() l.code = 400 - l.message = getString(R.string.login_get_avatar_failed) + l.message = getString(R.string.login_get_avatar_failed) return l } diff --git a/app/src/main/java/top/fumiama/copymanga/views/MangaCardView.kt b/app/src/main/java/top/fumiama/copymanga/views/MangaCardView.kt index 104c592..924aaaf 100644 --- a/app/src/main/java/top/fumiama/copymanga/views/MangaCardView.kt +++ b/app/src/main/java/top/fumiama/copymanga/views/MangaCardView.kt @@ -5,7 +5,7 @@ import android.util.AttributeSet import androidx.cardview.widget.CardView import java.io.File -class MangaCardView:CardView { +class MangaCardView :CardView { constructor(context: Context): super(context) constructor(context: Context, attrs: AttributeSet?): super (context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) diff --git a/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt b/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt index 108357c..ff2eb5e 100644 --- a/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt +++ b/app/src/main/java/top/fumiama/copymanga/views/ScaleImageView.kt @@ -16,6 +16,7 @@ import android.view.MotionEvent import android.widget.ImageView import top.fumiama.copymanga.ui.vm.PagesManager import top.fumiama.copymanga.ui.vm.ViewMangaActivity +import top.fumiama.dmzj.copymanga.R import java.lang.ref.WeakReference import java.util.* import kotlin.math.sqrt @@ -563,7 +564,7 @@ class ScaleImageView : ImageView { } }catch (e:Exception){ 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 { when { it <= 1.0 / 3.0 -> pm?.toPreviousPage() - it <= 2.0 / 3.0 -> pm?.manageInfo() + it <= 2.0 / 3.0 -> pm?.toggleDrawer() else -> pm?.toNextPage() } } diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index b8da36a..0b41be6 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -16,16 +16,13 @@ android:id="@+id/coordiv" android:layout_width="match_parent" android:layout_height="16dp" - android:background="?attr/colorPrimarySurface" - android:visibility="visible" - app:layout_scrollFlags="scroll|enterAlways" /> + android:background="?attr/colorPrimarySurface" /> diff --git a/app/src/main/res/layout/card_book.xml b/app/src/main/res/layout/card_book.xml index 9639348..bc8bebb 100644 --- a/app/src/main/res/layout/card_book.xml +++ b/app/src/main/res/layout/card_book.xml @@ -37,6 +37,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + 拷贝漫画 + top.fumiama.copymanga.fileprovider + 设定 关于 下载 @@ -40,6 +42,17 @@ 网络错误 保存封面失败 保存封面超时 + 下次浏览生效 + 已经到头了~ + 再次按下加载上一章 + 再次按下加载下一章 + 读取本地章节信息失败 + 下载章节信息失败 + 加载漫画错误 + 统计zip图片数错误 + 第%1$d页加载异常 + 加载章节错误 + 图片加载错误,请尝试下载后使用较低图片质量查看 https://%1$s/api/v3/h5/homeIndex?platform=3 https://%1$s @@ -153,4 +166,5 @@ 前往旧版下载 选择您的操作 + 选择如何打开漫画下载目录 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/themes.xml similarity index 100% rename from app/src/main/res/values/styles.xml rename to app/src/main/res/values/themes.xml diff --git a/app/src/main/res/values/weeks.xml b/app/src/main/res/values/weeks.xml new file mode 100644 index 0000000..c94d901 --- /dev/null +++ b/app/src/main/res/values/weeks.xml @@ -0,0 +1,12 @@ + + + + 周日 + 周一 + 周二 + 周三 + 周四 + 周五 + 周六 + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8819a1c..1d8133f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,4 +23,3 @@ android.enableR8.fullMode=true android.defaults.buildfeatures.buildconfig=true android.nonTransitiveRClass=false android.nonFinalResIds=false -org.gradle.unsafe.configuration-cache=true \ No newline at end of file