mirror of
https://github.com/fumiama/copymanga.git
synced 2026-06-05 07:20:23 +08:00
v2.4.3
新增 1. 更改默认 API (fix #131) 2. 按钮颜色随状态改变 (close #123) 修复 1. “我的订阅”中已阅读的话数可能会显示为乱码 (fix #128) 2. 搜索错误显示转码后结果 3. 搜索框输入关键词异常回显 (fix #109) 优化 1. 详情页排版 (fix #124) 升级 1. gson -> 2.13.1 2. lottie -> 6.6.6
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
applicationId 'top.fumiama.copymanga'
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 34
|
||||
versionCode 69
|
||||
versionName '2.4.2'
|
||||
versionCode 70
|
||||
versionName '2.4.3'
|
||||
resourceConfigurations += ['zh', 'zh-rCN']
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
@@ -114,13 +114,13 @@ dependencies {
|
||||
implementation 'com.github.bumptech.glide:glide:4.16.0'
|
||||
//noinspection KaptUsageInsteadOfKsp
|
||||
kapt 'com.github.bumptech.glide:compiler:4.16.0'
|
||||
implementation 'com.google.code.gson:gson:2.12.1'
|
||||
implementation 'com.google.code.gson:gson:2.13.1'
|
||||
implementation 'com.github.vovaksenov99:OverscrollableScrollView:1.0'
|
||||
implementation 'com.github.liaoinstan.SpringView:library:0a24d3e9dd'
|
||||
implementation 'com.github.zawadz88:MaterialPopupMenu:4.1.0'
|
||||
implementation files('libs/com.lapism/search-2.4.1.aar') // https://stackoverflow.com/a/63029110/28801553
|
||||
//noinspection GradleDependency
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.7.0'
|
||||
implementation 'com.airbnb.android:lottie:6.6.4'
|
||||
implementation 'com.airbnb.android:lottie:6.6.6'
|
||||
implementation 'net.java.dev.jna:jna:5.17.0@aar'
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ object Config {
|
||||
if (field != null) return field
|
||||
field = Proxy(
|
||||
R.string.apiProxyApiUrl,
|
||||
Regex("^https://(api|www)\\.(copymanga|mangacopy|copy-manga)\\.\\w+/api/"),
|
||||
Regex("^https://(api|www)\\.(copymanga|mangacopy|copy-manga|copy20)\\.\\w+/api/"),
|
||||
)
|
||||
return field
|
||||
}
|
||||
|
||||
36
app/src/main/java/top/fumiama/copymanga/strings/Chinese.kt
Normal file
36
app/src/main/java/top/fumiama/copymanga/strings/Chinese.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package top.fumiama.copymanga.strings
|
||||
|
||||
object Chinese {
|
||||
/**
|
||||
* 如果输入字符串中已包含汉字,直接返回。
|
||||
* 否则尝试以 UTF8 重新解码。
|
||||
*/
|
||||
fun fixEncodingIfNeeded(input: String): String {
|
||||
// 如果本身包含汉字,直接返回
|
||||
if (containsChinese(input)) {
|
||||
return input
|
||||
}
|
||||
|
||||
return try {
|
||||
val decoded = input.toByteArray(Charsets.ISO_8859_1).decodeToString()
|
||||
|
||||
// 检测解码后的是否包含汉字
|
||||
if (containsChinese(decoded)) {
|
||||
decoded
|
||||
} else {
|
||||
input // 解码后也没有汉字,说明可能不是编码问题
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
input
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单检测字符串是否包含常见 CJK(中日韩)汉字。
|
||||
*/
|
||||
fun containsChinese(text: String): Boolean {
|
||||
val regex = Regex("[\u4E00-\u9FFF]")
|
||||
return regex.containsMatchIn(text)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,15 +3,18 @@ package top.fumiama.copymanga.ui.book
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context.MODE_PRIVATE
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import kotlinx.android.synthetic.main.app_bar_main.*
|
||||
import kotlinx.android.synthetic.main.card_book.*
|
||||
import kotlinx.android.synthetic.main.fragment_book.*
|
||||
import kotlinx.android.synthetic.main.line_bookinfo_text.*
|
||||
import kotlinx.android.synthetic.main.line_booktandb.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -19,6 +22,7 @@ import kotlinx.coroutines.withContext
|
||||
import top.fumiama.copymanga.MainActivity
|
||||
import top.fumiama.copymanga.api.manga.Book
|
||||
import top.fumiama.copymanga.api.manga.Reader
|
||||
import top.fumiama.copymanga.strings.Chinese
|
||||
import top.fumiama.copymanga.view.template.NoBackRefreshFragment
|
||||
import top.fumiama.copymanga.view.interaction.Navigate
|
||||
import top.fumiama.copymanga.ui.comicdl.ComicDlFragment
|
||||
@@ -98,6 +102,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
activity?.apply {
|
||||
toolbar.title = book?.name
|
||||
}
|
||||
setReadTo()
|
||||
setStartRead()
|
||||
}
|
||||
|
||||
@@ -118,16 +123,13 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
activity?.apply {
|
||||
book?.name?.let { name ->
|
||||
getPreferences(MODE_PRIVATE).getInt(name, -1).let { p ->
|
||||
this@BookFragment.lbbstart.apply {
|
||||
var i = 0
|
||||
if(p >= 0) mBookHandler!!.chapterNames.let {
|
||||
i = if (p >= it.size) it.size-1 else p
|
||||
text = it[i]
|
||||
}
|
||||
setOnClickListener {
|
||||
mBookHandler?.apply {
|
||||
Reader.start2viewManga(name, i, urlArray, uuidArray)
|
||||
}
|
||||
var i = 0
|
||||
if(p >= 0) mBookHandler!!.chapterNames.let {
|
||||
i = if (p >= it.size) it.size-1 else p
|
||||
}
|
||||
this@BookFragment.lbbstart.setOnClickListener {
|
||||
mBookHandler?.apply {
|
||||
Reader.start2viewManga(name, i, urlArray, uuidArray)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,6 +137,23 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
}
|
||||
}
|
||||
|
||||
fun setReadTo() {
|
||||
var chapter = "未读"
|
||||
if(!mBookHandler?.chapterNames.isNullOrEmpty()) {
|
||||
activity?.apply {
|
||||
book?.name?.let { name ->
|
||||
getPreferences(MODE_PRIVATE).getInt(name, -1).let { p ->
|
||||
if(p >= 0) mBookHandler!!.chapterNames.let {
|
||||
chapter = it[if (p >= it.size) it.size-1 else p]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
chapter = "读至 $chapter"
|
||||
this@BookFragment.bttag.text = chapter
|
||||
}
|
||||
|
||||
private suspend fun prepareHandler() = withContext(Dispatchers.IO) {
|
||||
arguments?.apply {
|
||||
if (getBoolean("loadJson")) {
|
||||
@@ -175,7 +194,7 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
mBookHandler?.collect = b.results?.collect?:-2
|
||||
Log.d("MyBF", "get collect of ${book?.path} = ${mBookHandler?.collect}")
|
||||
tic.text = b.results?.browse?.chapter_name?.let { name ->
|
||||
getString(R.string.text_format_cloud_read_to).format(name)
|
||||
getString(R.string.text_format_cloud_read_to).format(Chinese.fixEncodingIfNeeded(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +206,11 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
queryCollect()
|
||||
mBookHandler?.collect?.let { collect ->
|
||||
if (collect > 0) {
|
||||
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
|
||||
this@BookFragment.lbbsub.apply {
|
||||
setText(R.string.button_sub_subscribed)
|
||||
val color = MaterialColors.getColor(this, R.attr.colorButtonNormal)
|
||||
backgroundTintList = ColorStateList.valueOf(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
book?.uuid?.let { uuid ->
|
||||
@@ -199,7 +222,11 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
val re = MainActivity.shelf?.del(collect)
|
||||
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
|
||||
if (re == "请求成功") {
|
||||
this@BookFragment.lbbsub.setText(R.string.button_sub)
|
||||
this@BookFragment.lbbsub.apply {
|
||||
setText(R.string.button_sub)
|
||||
val color = MaterialColors.getColor(this, R.attr.colorPrimarySurface)
|
||||
backgroundTintList = ColorStateList.valueOf(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@clickLaunch
|
||||
@@ -208,7 +235,11 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) {
|
||||
Toast.makeText(context, re, Toast.LENGTH_SHORT).show()
|
||||
if (re == "修改成功") {
|
||||
queryCollect()
|
||||
this@BookFragment.lbbsub.setText(R.string.button_sub_subscribed)
|
||||
this@BookFragment.lbbsub.apply {
|
||||
setText(R.string.button_sub_subscribed)
|
||||
val color = MaterialColors.getColor(this, R.attr.colorButtonNormal)
|
||||
backgroundTintList = ColorStateList.valueOf(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
|
||||
oa.start()
|
||||
}
|
||||
complete = true
|
||||
that?.setReadTo()
|
||||
that?.setStartRead()
|
||||
that?.setAddToShelf()
|
||||
Log.d("MyBH", "Set complete: true")
|
||||
@@ -126,7 +127,7 @@ class BookHandler(private val th: WeakReference<BookFragment>): Handler(Looper.m
|
||||
// tic?.visibility = View.GONE
|
||||
activity?.toolbar?.title = book?.name
|
||||
btauth?.text = that?.getString(R.string.text_format_region)?.format(book?.region?:"未知")
|
||||
bttag?.text = that?.getString(R.string.text_format_img_type)?.format(book?.imageType?:"未知")
|
||||
// bttag?.text = that?.getString(R.string.text_format_img_type)?.format(book?.imageType?:"未知")
|
||||
bthit?.text = that?.getString(R.string.text_format_hit)?.format(book?.popular?:-1)
|
||||
btsub?.text = that?.getString(R.string.text_format_stat)?.format(book?.status?:"未知")
|
||||
bttime?.text = book?.updateTime?:"未知"
|
||||
|
||||
@@ -5,6 +5,8 @@ import android.util.Log
|
||||
import top.fumiama.copymanga.view.template.InfoCardLoader
|
||||
import top.fumiama.copymanga.api.Config
|
||||
import top.fumiama.dmzj.copymanga.R
|
||||
import java.net.URLEncoder
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class SearchFragment : InfoCardLoader(R.layout.fragment_search, R.id.action_nav_search_to_nav_book) {
|
||||
@@ -16,7 +18,7 @@ class SearchFragment : InfoCardLoader(R.layout.fragment_search, R.id.action_nav_
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
if (isFirstInflate) {
|
||||
query = arguments?.getCharSequence("query")?.toString()
|
||||
query = arguments?.getCharSequence("query")?.toString()?.let { q -> URLEncoder.encode(q, Charset.defaultCharset().name()) }
|
||||
type = arguments?.getString("type")
|
||||
Log.d("MySF", "get query=$query, type=$type")
|
||||
}
|
||||
|
||||
@@ -96,13 +96,14 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
|
||||
var lastChangeTime = 0L
|
||||
override fun onQueryTextChange(newText: CharSequence): Boolean {
|
||||
if (newText.contentEquals("__notice_focus_change__") || newText.contentEquals(lastSearch)) return true
|
||||
lastSearch = newText.toString()
|
||||
postDelayed({
|
||||
lifecycleScope.launch {
|
||||
if (!newText.contentEquals(lastSearch)) return@launch
|
||||
val diff = System.currentTimeMillis() - lastChangeTime
|
||||
if(diff > 500) {
|
||||
if (newText.isNotEmpty()) {
|
||||
Log.d("MyHF", "new text: $newText")
|
||||
lastSearch = newText.toString()
|
||||
adapter.refresh(newText)
|
||||
}
|
||||
}
|
||||
@@ -295,9 +296,10 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) {
|
||||
override fun getItemCount() = (results?.results?.list?.size?:0) + if (query?.isNotEmpty() == true) 1 else 0
|
||||
|
||||
suspend fun refresh(q: CharSequence) = withContext(Dispatchers.IO) {
|
||||
query = URLEncoder.encode(q.toString(), Charset.defaultCharset().name())
|
||||
query = q.toString()
|
||||
activity?.apply {
|
||||
PausableDownloader(getString(R.string.searchApiUrl).format(Config.myHostApiUrl.value, 0, query, type)) {
|
||||
PausableDownloader(getString(R.string.searchApiUrl).format(Config.myHostApiUrl.value, 0,
|
||||
URLEncoder.encode(q.toString(), Charset.defaultCharset().name()), type)) {
|
||||
results = Gson().fromJson(it.decodeToString(), BookListStructure::class.java)
|
||||
count = results?.results?.total?:0
|
||||
withContext(Dispatchers.Main) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import top.fumiama.copymanga.json.HistoryBookListStructure
|
||||
import top.fumiama.copymanga.json.ShelfStructure
|
||||
import top.fumiama.copymanga.json.TypeBookListStructure
|
||||
import top.fumiama.copymanga.net.template.PausableDownloader
|
||||
import top.fumiama.copymanga.strings.Chinese
|
||||
import top.fumiama.copymanga.view.interaction.Navigate
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@@ -66,7 +67,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
|
||||
Log.d("MyICL", "load @ $i")
|
||||
if(ad?.exit == true) return@PausableDownloader
|
||||
cardList?.addCard(
|
||||
book?.comic?.name?:"null", "\n云读至${book?.last_chapter_name}", book?.comic?.cover,
|
||||
book?.comic?.name?:"null", "\n云读至${book?.last_chapter_name?.let { Chinese.fixEncodingIfNeeded(it) }}", book?.comic?.cover,
|
||||
book?.comic?.path_word, null, null,
|
||||
book?.comic?.status==1
|
||||
)
|
||||
@@ -88,7 +89,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT
|
||||
Log.d("MyICL", "load @ $i")
|
||||
if(ad?.exit == true) return@PausableDownloader
|
||||
cardList?.addCard(
|
||||
book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到$it" }?:"未读"}", book?.comic?.cover,
|
||||
book?.comic?.name?:"null", "\n${book?.last_browse?.last_browse_name?.let { "读到${Chinese.fixEncodingIfNeeded(it)}" }?:"未读"}", book?.comic?.cover,
|
||||
book?.comic?.path_word, null, null,
|
||||
book?.comic?.status==1,
|
||||
book.comic?.browse?.chapter_uuid != book.comic?.last_chapter_id
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE resources [
|
||||
<!ENTITY hosturl "www.copy-manga.com">
|
||||
<!ENTITY appver "2.2.6">
|
||||
<!ENTITY hosturl "www.copy20.com">
|
||||
<!ENTITY appver "2.2.9">
|
||||
]>
|
||||
<resources>
|
||||
<string name="app_name">拷贝漫画</string>
|
||||
@@ -123,7 +123,6 @@
|
||||
<string name="text_format_hit">热度 %1$d</string>
|
||||
<string name="text_format_stat">状态 %1$s</string>
|
||||
<string name="text_format_region">区域 %1$s</string>
|
||||
<string name="text_format_img_type">画幅 %1$s</string>
|
||||
<string name="text_format_cloud_read_to">云读至%1$s</string>
|
||||
|
||||
<string name="topics_series">专题系列</string>
|
||||
|
||||
Reference in New Issue
Block a user