From 98b2d1a4ae0ab33c13fc1d402ae55aead85ea34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 24 May 2025 21:40:50 +0900 Subject: [PATCH] =?UTF-8?q?v2.5.0=20=E6=96=B0=E5=A2=9E=201.=20=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=B7=B2=E4=B8=8B=E8=BD=BD=E6=BC=AB=E7=94=BB=E4=B8=BA?= =?UTF-8?q?zip=E5=8E=8B=E7=BC=A9=E5=8C=85=202.=20=E6=B5=85=E8=89=B2?= =?UTF-8?q?=E5=92=8C=E6=B7=B1=E8=89=B2=E6=A8=A1=E5=BC=8F=E5=88=87=E6=8D=A2?= =?UTF-8?q?=20(fix=20#136)=203.=20=E6=94=AF=E6=8C=81=E8=87=AA=E5=BB=BA?= =?UTF-8?q?=E5=8F=8D=E5=90=91API=E4=BB=A3=E7=90=86=20(=E4=B8=8D=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=9B=BE=E7=89=87)=204.=20=E6=88=91=E7=9A=84=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E6=98=BE=E7=A4=BA=E6=9C=AC=E5=9C=B0=E9=98=85=E8=AF=BB?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6=20(fix=20#46)=205.=20=E5=80=92=E5=BA=8F?= =?UTF-8?q?=E6=8E=92=E5=88=97=E6=AF=8F=E4=B8=80=E7=AB=A0=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- .../top/fumiama/copymanga/MainActivity.kt | 36 ++++-- .../java/top/fumiama/copymanga/api/Config.kt | 61 +++++++++- .../top/fumiama/copymanga/api/manga/Book.kt | 8 +- .../top/fumiama/copymanga/api/manga/Reader.kt | 37 ++++++ .../top/fumiama/copymanga/api/manga/Shelf.kt | 4 +- .../top/fumiama/copymanga/api/manga/Volume.kt | 2 +- .../top/fumiama/copymanga/api/user/Member.kt | 6 +- .../copymanga/json/NetworkStructure.java | 9 ++ .../java/top/fumiama/copymanga/lib/Comandy.kt | 2 +- .../copymanga/lib/template/LazyLibrary.kt | 110 +++++++++--------- .../copymanga/net/ComandyGlideModule.kt | 5 +- .../fumiama/copymanga/net/DownloadTools.kt | 60 ++++++---- .../java/top/fumiama/copymanga/net/Proxy.kt | 1 + .../net/template/AutoDownloadHandler.kt | 8 +- .../fumiama/copymanga/storage/FileUtils.kt | 57 +++++++++ .../fumiama/copymanga/ui/book/BookFragment.kt | 12 +- .../fumiama/copymanga/ui/book/BookHandler.kt | 13 ++- .../ui/cardflow/history/HistoryFragment.kt | 2 +- .../ui/cardflow/newest/NewestFragment.kt | 2 +- .../ui/cardflow/rank/RankFragment.kt | 2 +- .../ui/cardflow/recommend/RecFragment.kt | 2 +- .../ui/cardflow/search/SearchFragment.kt | 2 +- .../ui/cardflow/shelf/ShelfFragment.kt | 2 +- .../ui/cardflow/sort/SortFragment.kt | 4 +- .../ui/cardflow/topic/TopicFragment.kt | 4 +- .../ui/download/NewDownloadFragment.kt | 74 ++++++++++-- .../fumiama/copymanga/ui/home/HomeFragment.kt | 2 +- .../fumiama/copymanga/ui/home/HomeHandler.kt | 5 +- .../copymanga/ui/settings/SettingsFragment.kt | 20 ++++ .../top/fumiama/copymanga/ui/vm/VMHandler.kt | 2 +- .../copymanga/view/template/InfoCardLoader.kt | 46 ++++++++ .../copymanga/view/template/StatusCardFlow.kt | 2 +- .../copymanga/view/template/ThemeCardFlow.kt | 2 +- app/src/main/res/values/arrays.xml | 10 ++ app/src/main/res/values/strings.xml | 25 +++- app/src/main/res/xml/pref_setting.xml | 34 +++++- 37 files changed, 509 insertions(+), 168 deletions(-) create mode 100644 app/src/main/java/top/fumiama/copymanga/json/NetworkStructure.java diff --git a/app/build.gradle b/app/build.gradle index 46a7a25..b6daf84 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId 'top.fumiama.copymanga' minSdkVersion 23 targetSdkVersion 34 - versionCode 70 - versionName '2.4.3' + versionCode 71 + versionName '2.5.0' resourceConfigurations += ['zh', 'zh-rCN'] testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt index 3ed4a79..337fc87 100644 --- a/app/src/main/java/top/fumiama/copymanga/MainActivity.kt +++ b/app/src/main/java/top/fumiama/copymanga/MainActivity.kt @@ -23,6 +23,7 @@ import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.net.toUri @@ -81,6 +82,19 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) + val darkModePrefKey = getString(R.string.darkModeKeyID) + PreferenceManager.getDefaultSharedPreferences(this)?.apply { + if (contains(darkModePrefKey)) getString(darkModePrefKey, "0")?.toInt()?.let { + if (it > 0) { + AppCompatDelegate.setDefaultNightMode(listOf( + AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, + AppCompatDelegate.MODE_NIGHT_NO, + AppCompatDelegate.MODE_NIGHT_YES, + )[it]) + } + } + } + // must init before setContentView because HomeF need them to init mainWeakReference = WeakReference(this) toolsBox = UITools(this) @@ -172,13 +186,13 @@ class MainActivity : AppCompatActivity() { )[it]) } } - if (Config.general_enable_transparent_system_bar.value) { - WindowCompat.setDecorFitsSystemWindows(window, false) - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - window.statusBarColor = 0 - window.navigationBarColor = 0 - } + } + if (Config.general_enable_transparent_system_bar.value) { + WindowCompat.setDecorFitsSystemWindows(window, false) + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) + window.statusBarColor = 0 + window.navigationBarColor = 0 } } @@ -197,7 +211,11 @@ class MainActivity : AppCompatActivity() { true } R.id.action_download -> { - bookHandler.get()?.sendEmptyMessage(BookHandler.NAVIGATE_TO_DOWNLOAD) + if (NewDownloadFragment.wn != null) { + //TODO: fill it + } else { + bookHandler.get()?.sendEmptyMessage(BookHandler.NAVIGATE_TO_DOWNLOAD) + } true } R.id.action_sort -> { @@ -412,7 +430,7 @@ class MainActivity : AppCompatActivity() { dl.setMessage("${getString(R.string.app_description)}\n" + "\n$comandy\n" + "$comancry\n\n"+ File("/proc/self/cmdline").readText() + "\n" + - "安装位置: ${applicationInfo.sourceDir}") + "当前API: ${Config.myHostApiUrl.joinToString(", ")}") dl.setTitle("${getString(R.string.action_info)} ${BuildConfig.VERSION_NAME}") dl.setIcon(R.mipmap.ic_launcher) dl.setPositiveButton(android.R.string.ok) { _, _ -> } diff --git a/app/src/main/java/top/fumiama/copymanga/api/Config.kt b/app/src/main/java/top/fumiama/copymanga/api/Config.kt index 4a15f07..9ddb20c 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/Config.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/Config.kt @@ -1,14 +1,21 @@ package top.fumiama.copymanga.api +import android.util.Log import com.bumptech.glide.load.model.LazyHeaders +import com.google.gson.Gson +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import top.fumiama.copymanga.MainActivity +import top.fumiama.copymanga.json.NetworkStructure +import top.fumiama.copymanga.net.DownloadTools +import top.fumiama.copymanga.net.Proxy +import top.fumiama.copymanga.net.Resolution import top.fumiama.copymanga.storage.PreferenceBoolean import top.fumiama.copymanga.storage.PreferenceInt import top.fumiama.copymanga.storage.PreferenceString import top.fumiama.copymanga.storage.UserPreferenceInt import top.fumiama.copymanga.storage.UserPreferenceString -import top.fumiama.copymanga.net.Proxy -import top.fumiama.copymanga.net.Resolution import top.fumiama.dmzj.copymanga.R import java.io.File @@ -53,9 +60,52 @@ object Config { return field } - val myHostApiUrl = PreferenceString("settings_cat_net_et_api_url", R.string.hostUrl) + val proxyUrl = MainActivity.mainWeakReference?.get()?.getString(R.string.proxyUrl)!! + private val reverseProxyUrl = PreferenceString(R.string.reverseProxyKeyID) + private val networkApiUrl = PreferenceString("settings_cat_net_et_api_url", R.string.hostUrl) + private var mHostApiUrls: Array = arrayOf() + private var mHostApiUrlsMutex = Mutex() + val myHostApiUrl: Array + get() { + if (mHostApiUrls.isNotEmpty()) return mHostApiUrls + if (reverseProxyUrl.value.isNotEmpty() && reverseProxyUrl.value != proxyUrl) { + mHostApiUrls = arrayOf(reverseProxyUrl.value) + Log.d("MyC", "myHostApiUrl set reverse proxy to ${mHostApiUrls[0]}") + return mHostApiUrls + } + MainActivity.mainWeakReference?.get()?.apply { + runBlocking { + mHostApiUrlsMutex.withLock { + if (mHostApiUrls.isNotEmpty()) return@runBlocking + try { + val u = getString(R.string.networkApiUrl).format(networkApiUrl.value) + val r = Gson().fromJson((apiProxy?.comancry(u) { + DownloadTools.getHttpContent(it, referer, pc_ua) + }?:DownloadTools.getHttpContent(u, referer, pc_ua)).decodeToString(), NetworkStructure::class.java) + if (r != null) { + Log.d("MyC", "myHostApiUrl get code ${r.code} msg ${r.message}") + if (r.code == 200 && r.results != null) { + // need header umstring + // r.results.api.forEach { it.forEach { api -> if (!api.isNullOrEmpty() && api !in field) field += api } } + r.results.share.forEach { api -> if (!api.isNullOrEmpty() && api !in mHostApiUrls) mHostApiUrls += api } + } + } + } catch (e: Exception) { + e.printStackTrace() + mHostApiUrls = arrayOf(networkApiUrl.value) + } + if (mHostApiUrls.isEmpty()) { + mHostApiUrls = arrayOf(networkApiUrl.value) + Log.d("MyC", "myHostApiUrl set default ${mHostApiUrls[0]}") + } + } + } + } + Log.d("MyC", "myHostApiUrl get hosts ${mHostApiUrls.joinToString(", ")}") + return mHostApiUrls + } val navTextInfo = UserPreferenceString("navTextInfo", R.string.navTextInfo) - val proxy_key = PreferenceString(R.string.imgProxyKeyID) + val proxy_key = PreferenceString(R.string.imgProxyCodeKeyID) val app_ver = PreferenceString("settings_cat_general_et_app_version", R.string.app_ver) val token = UserPreferenceString("token", "", null) val pc_ua get() = MainActivity.mainWeakReference?.get()?.getString(R.string.pc_ua)?.format(app_ver.value)?:"" @@ -80,6 +130,7 @@ object Config { val net_use_api_proxy = PreferenceBoolean("settings_cat_net_sw_use_api_proxy", false) val net_img_resolution = PreferenceString(R.string.imgResolutionKeyID) + val view_manga_inverse_chapters = PreferenceBoolean("settings_cat_vm_sw_inverse_chapters", false) val view_manga_always_dark_bg = PreferenceBoolean("settings_cat_vm_sw_always_dark_bg", false) val view_manga_vertical_max = PreferenceInt("settings_cat_vm_sb_vertical_max", 20) val view_manga_quality = PreferenceInt("settings_cat_vm_sb_quality", 100) @@ -92,5 +143,5 @@ object Config { fun getChapterInfoApiUrl(path: String?, uuid: String?, version: Int) = MainActivity.mainWeakReference?.get()?.getString(R.string.chapterInfoApiUrl) - ?.format(myHostApiUrl.value, path, if (version >= 2) "$version" else "" , uuid) + ?.format(myHostApiUrl.random(), path, if (version >= 2) "$version" else "" , uuid) } diff --git a/app/src/main/java/top/fumiama/copymanga/api/manga/Book.kt b/app/src/main/java/top/fumiama/copymanga/api/manga/Book.kt index 3979006..2a9865f 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/manga/Book.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/manga/Book.kt @@ -15,7 +15,7 @@ import top.fumiama.dmzj.copymanga.R import java.io.File class Book(val path: String, private val getString: (Int) -> String, private val exDir: File, private val loadCache: Boolean = false, private val mPassName: String? = null) { - private val mBookApiUrl = getString(R.string.bookInfoApiUrl).format(Config.myHostApiUrl.value, path) + private val mBookApiUrl = getString(R.string.bookInfoApiUrl).format(Config.myHostApiUrl.random(), path) private val mUserAgent = getString(R.string.pc_ua).format(Config.app_ver.value) private var mBook: BookInfoStructure? = null private var mGroupPathWords = arrayOf() @@ -37,12 +37,6 @@ class Book(val path: String, private val getString: (Int) -> String, private val val author: Array? get() = mBook?.results?.comic?.author val theme: Array? get() = mBook?.results?.comic?.theme val keys get() = mKeys - val imageType: String - get() = when(mBook?.results?.comic?.img_type) { - 1 -> "条漫" - 2 -> "普通" - else -> "未知类型${mBook?.results?.comic?.img_type}" - } val popular get() = mBook?.results?.comic?.popular?:0 val status get() = mBook?.results?.comic?.status?.display?:"未知" val updateTime get() = mBook?.results?.comic?.datetime_updated?:"未知" diff --git a/app/src/main/java/top/fumiama/copymanga/api/manga/Reader.kt b/app/src/main/java/top/fumiama/copymanga/api/manga/Reader.kt index 02e1448..a1f8f58 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/manga/Reader.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/manga/Reader.kt @@ -1,12 +1,16 @@ package top.fumiama.copymanga.api.manga import android.content.Context +import android.content.Context.MODE_PRIVATE import android.content.Intent import android.util.Log import androidx.core.content.edit +import androidx.fragment.app.FragmentActivity import com.google.gson.Gson import kotlinx.android.synthetic.main.button_tbutton.view.* +import kotlinx.coroutines.delay import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference +import top.fumiama.copymanga.api.Config import top.fumiama.copymanga.json.VolumeStructure import top.fumiama.copymanga.ui.vm.ViewMangaActivity import java.io.File @@ -81,4 +85,37 @@ object Reader { } return "N/A:null_gson" } + fun getComicChapterNamesInFolder(file: File): Array { + if(!file.exists()) { + return arrayOf() + } + val jsonFile = File(file, "info.json") + if(!jsonFile.exists()) { + return arrayOf() + } + Gson().fromJson(jsonFile.readText(), Array::class.java)?.let { volumes -> + if(volumes.isEmpty()) { + return arrayOf() + } + var arr = arrayOf() + volumes.forEach { v -> + v.results?.list?.forEach { + arr += it.name?:"" + } + } + return arr + } + return arrayOf() + } + fun getLocalReadingProgress(activity: FragmentActivity, name: String, chapterNames: Array): String { + var chapter = "未读" + activity.apply { + getPreferences(MODE_PRIVATE).getInt(name, -1).let { p -> + if(p >= 0) chapterNames.let { + chapter = it[if (p >= it.size) it.size-1 else p] + } + } + } + return chapter + } } diff --git a/app/src/main/java/top/fumiama/copymanga/api/manga/Shelf.kt b/app/src/main/java/top/fumiama/copymanga/api/manga/Shelf.kt index 8cfbbc2..0fdf8e2 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/manga/Shelf.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/manga/Shelf.kt @@ -10,7 +10,7 @@ import top.fumiama.copymanga.net.DownloadTools import top.fumiama.dmzj.copymanga.R class Shelf(private val getString: (Int) -> String) { - private val apiUrl: String get() = getString(R.string.shelfOperateApiUrl).format(Config.myHostApiUrl.value) + private val apiUrl: String get() = getString(R.string.shelfOperateApiUrl).format(Config.myHostApiUrl.random()) private val queryApiUrlTemplate = getString(R.string.bookUserQueryApiUrl) private val addApiUrl get() = "$apiUrl?platform=3" private val delApiUrl get() = "${apiUrl}s?platform=3" @@ -68,7 +68,7 @@ class Shelf(private val getString: (Int) -> String) { suspend fun query(pathWord: String): BookQueryStructure? = withContext(Dispatchers.IO) { try { - val queryUrl = queryApiUrlTemplate.format(Config.myHostApiUrl.value, pathWord) + val queryUrl = queryApiUrlTemplate.format(Config.myHostApiUrl.random(), pathWord) (Config.apiProxy?.comancry(queryUrl) { url -> DownloadTools.getHttpContent(url, Config.referer) }?:DownloadTools.getHttpContent(queryUrl, Config.referer)).let { diff --git a/app/src/main/java/top/fumiama/copymanga/api/manga/Volume.kt b/app/src/main/java/top/fumiama/copymanga/api/manga/Volume.kt index 51b7b27..ea1c397 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/manga/Volume.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/manga/Volume.kt @@ -39,7 +39,7 @@ class Volume(private val path: String, private val groupPathWord: String, getStr return@withContext mVolume } - private fun getApiUrl(offset: Int) = mGroupInfoApiUrlTemplate.format(Config.myHostApiUrl.value, path, groupPathWord, offset) + private fun getApiUrl(offset: Int) = mGroupInfoApiUrlTemplate.format(Config.myHostApiUrl.random(), path, groupPathWord, offset) private suspend fun download(re: Array, offset: Int, c: Int) = withContext(Dispatchers.IO) { Log.d("MyV", "下载偏移: $offset") getApiUrl(offset).let { diff --git a/app/src/main/java/top/fumiama/copymanga/api/user/Member.kt b/app/src/main/java/top/fumiama/copymanga/api/user/Member.kt index b23d011..d109c8a 100644 --- a/app/src/main/java/top/fumiama/copymanga/api/user/Member.kt +++ b/app/src/main/java/top/fumiama/copymanga/api/user/Member.kt @@ -49,7 +49,7 @@ class Member(private val getString: (Int) -> String) { } try { val u = getString(R.string.memberInfoApiUrl) - .format(Config.myHostApiUrl.value) + .format(Config.myHostApiUrl.random()) val data = (Config.apiProxy?.comancry(u) { DownloadTools.getHttpContent(it) }?:DownloadTools.getHttpContent(u)).decodeToString() @@ -97,7 +97,7 @@ class Member(private val getString: (Int) -> String) { } private suspend fun postLogin(username: String, pwd: String, salt: Int): ByteArray? = - getString(R.string.loginApiUrl).format(Config.myHostApiUrl.value).let { u -> + getString(R.string.loginApiUrl).format(Config.myHostApiUrl.random()).let { u -> val use: suspend (String) -> ByteArray? = { it: String -> DownloadTools.getApiConnection(it, "POST").let { c -> c.doOutput = true @@ -129,7 +129,7 @@ class Member(private val getString: (Int) -> String) { private suspend fun postComandyLogin(username: String, pwd: String, salt: Int) = - getString(R.string.loginApiUrl).format(Config.myHostApiUrl.value).let { u -> + getString(R.string.loginApiUrl).format(Config.myHostApiUrl.random()).let { u -> val use: suspend (String) -> ByteArray? = { it: String -> DownloadTools.getComandyApiConnection(it, "POST", null, Config.pc_ua).apply { headers["content-type"] = "application/x-www-form-urlencoded;charset=utf-8" diff --git a/app/src/main/java/top/fumiama/copymanga/json/NetworkStructure.java b/app/src/main/java/top/fumiama/copymanga/json/NetworkStructure.java new file mode 100644 index 0000000..a39ca17 --- /dev/null +++ b/app/src/main/java/top/fumiama/copymanga/json/NetworkStructure.java @@ -0,0 +1,9 @@ +package top.fumiama.copymanga.json; + +public class NetworkStructure extends ReturnBase { + public Results results; + public static class Results { + public String[] share; + public String[][] api; + } +} diff --git a/app/src/main/java/top/fumiama/copymanga/lib/Comandy.kt b/app/src/main/java/top/fumiama/copymanga/lib/Comandy.kt index 4c808a8..ad302a8 100644 --- a/app/src/main/java/top/fumiama/copymanga/lib/Comandy.kt +++ b/app/src/main/java/top/fumiama/copymanga/lib/Comandy.kt @@ -16,7 +16,7 @@ class Comandy: LazyLibrary( Log.d("MyComandy", "$name block enabled for isInInit") return false } - if (mEnabled != true && DownloadTools.failTimes.get() >= 3) { + if (mEnabled != true && DownloadTools.failTimes.get() >= 16) { mEnabled = true return true } diff --git a/app/src/main/java/top/fumiama/copymanga/lib/template/LazyLibrary.kt b/app/src/main/java/top/fumiama/copymanga/lib/template/LazyLibrary.kt index 6afa9c3..ab8f4a4 100644 --- a/app/src/main/java/top/fumiama/copymanga/lib/template/LazyLibrary.kt +++ b/app/src/main/java/top/fumiama/copymanga/lib/template/LazyLibrary.kt @@ -2,20 +2,18 @@ package top.fumiama.copymanga.lib.template import android.os.Build import android.util.Log -import androidx.lifecycle.lifecycleScope import com.google.gson.Gson import com.sun.jna.Library import com.sun.jna.Native import kotlinx.android.synthetic.main.dialog_progress.view.* import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.json.ComandyVersion +import top.fumiama.copymanga.net.Client +import top.fumiama.copymanga.net.DownloadTools import top.fumiama.copymanga.storage.PreferenceBoolean import top.fumiama.copymanga.storage.UserPreferenceInt -import top.fumiama.copymanga.net.DownloadTools -import top.fumiama.copymanga.net.Client import top.fumiama.dmzj.copymanga.R import java.io.ByteArrayInputStream import java.io.File @@ -54,68 +52,66 @@ open class LazyLibrary( }?:return null Log.d("MyLazyLibrary", "$name arch: $prefix") MainActivity.mainWeakReference?.get()?.let { ma -> - ma.lifecycleScope.launch { - withContext(Dispatchers.IO) { - Log.d("MyLazyLibrary", "$name launched") - var f = File(ma.filesDir, "libs") - if (!f.exists()) f.mkdirs() - f = File(f, name) - var remoteVersion = 0 - if (f.exists()) { - DownloadTools.getHttpContent(ma.getString(R.string.comandy_version_url).format(repoName), -1)?.let dataLet@{ + withContext(Dispatchers.IO) { + Log.d("MyLazyLibrary", "$name launched") + var f = File(ma.filesDir, "libs") + if (!f.exists()) f.mkdirs() + f = File(f, name) + var remoteVersion = 0 + if (f.exists()) { + DownloadTools.getHttpContent(ma.getString(R.string.comandy_version_url).format(repoName), -1)?.let dataLet@{ + try { + val body = Gson().fromJson(it.decodeToString(), ComandyVersion::class.java)?.body + if (body?.startsWith("Version: ") == true) { + remoteVersion = body.substring(9).toInt() + } + } catch (e: Exception) { + e.printStackTrace() + } + val myVersion = version.value?:0 + if (myVersion >= remoteVersion) { + Log.d("MyLazyLibrary", "$name version $myVersion is latest") + isInInit.set(false) + mLibraryFile = f + return@withContext + } + Log.d("MyLazyLibrary", "$name version $myVersion <= latest $remoteVersion, update...") + } + } + withContext(Dispatchers.Main) { + val progressBar = ma.layoutInflater.inflate(R.layout.dialog_progress, null, false) + val progressHandler = object : Client.Progress{ + override fun notify(progressPercentage: Int) { + Log.d("MyLazyLibrary", "Set dl $name progress: $progressPercentage") + progressBar.dpp.progress = progressPercentage + } + } + val info = ma.toolsBox.buildAlertWithView("加载${functionName}组件", progressBar, "隐藏") + withContext(Dispatchers.IO) { + DownloadTools.getHttpContent(ma.getString(R.string.comandy_download_url).format(repoName, prefix, name), -1, progressHandler)?.let { + if(f.exists()) f.delete() try { - val body = Gson().fromJson(it.decodeToString(), ComandyVersion::class.java)?.body - if (body?.startsWith("Version: ") == true) { - remoteVersion = body.substring(9).toInt() + GZIPInputStream(ByteArrayInputStream(it)).use { dataIn -> + f.outputStream().use { dataOut -> + dataIn.copyTo(dataOut) + } + } + if (remoteVersion > 0) version.value = remoteVersion + Log.d("MyLazyLibrary", "update success") + isInInit.set(false) + withContext(Dispatchers.Main) { + info.dismiss() } } catch (e: Exception) { e.printStackTrace() - } - val myVersion = version.value?:0 - if (myVersion >= remoteVersion) { - Log.d("MyLazyLibrary", "$name version $myVersion is latest") - isInInit.set(false) - mLibraryFile = f - return@withContext - } - Log.d("MyLazyLibrary", "$name version $myVersion <= latest $remoteVersion, update...") - } - } - withContext(Dispatchers.Main) { - val progressBar = ma.layoutInflater.inflate(R.layout.dialog_progress, null, false) - val progressHandler = object : Client.Progress{ - override fun notify(progressPercentage: Int) { - Log.d("MyLazyLibrary", "Set dl $name progress: $progressPercentage") - progressBar.dpp.progress = progressPercentage - } - } - val info = ma.toolsBox.buildAlertWithView("加载${functionName}组件", progressBar, "隐藏") - withContext(Dispatchers.IO) { - DownloadTools.getHttpContent(ma.getString(R.string.comandy_download_url).format(repoName, prefix, name), -1, progressHandler)?.let { if(f.exists()) f.delete() - try { - GZIPInputStream(ByteArrayInputStream(it)).use { dataIn -> - f.outputStream().use { dataOut -> - dataIn.copyTo(dataOut) - } - } - if (remoteVersion > 0) version.value = remoteVersion - Log.d("MyLazyLibrary", "update success") - isInInit.set(false) - withContext(Dispatchers.Main) { - info.dismiss() - } - } catch (e: Exception) { - e.printStackTrace() - if(f.exists()) f.delete() - } } } } - mLibraryFile = if(f.exists()) f else null - return@withContext } - }.join() + mLibraryFile = if(f.exists()) f else null + return@withContext + } } return mLibraryFile } diff --git a/app/src/main/java/top/fumiama/copymanga/net/ComandyGlideModule.kt b/app/src/main/java/top/fumiama/copymanga/net/ComandyGlideModule.kt index 50cea24..8fbfe63 100644 --- a/app/src/main/java/top/fumiama/copymanga/net/ComandyGlideModule.kt +++ b/app/src/main/java/top/fumiama/copymanga/net/ComandyGlideModule.kt @@ -17,6 +17,7 @@ import com.bumptech.glide.module.AppGlideModule import com.bumptech.glide.signature.ObjectKey import com.google.gson.Gson import kotlinx.coroutines.runBlocking +import top.fumiama.copymanga.api.Config.proxyUrl import top.fumiama.copymanga.json.ComandyCapsule import top.fumiama.copymanga.lib.Comandy import java.nio.ByteBuffer @@ -86,7 +87,7 @@ class ComandyGlideModule: AppGlideModule() { override fun handles(model: GlideUrl): Boolean { return Comandy.instance.enabled && model.toURL().let { - it.protocol == "https" && it.host != "copymanga.azurewebsites.net" + it.protocol == "https" && it.host != proxyUrl } } @@ -105,7 +106,7 @@ class ComandyGlideModule: AppGlideModule() { override fun handles(model: String): Boolean { return Comandy.instance.enabled && model.startsWith("https://") && - !model.startsWith("https://copymanga.azurewebsites.net") + !model.startsWith("https://$proxyUrl") } } diff --git a/app/src/main/java/top/fumiama/copymanga/net/DownloadTools.kt b/app/src/main/java/top/fumiama/copymanga/net/DownloadTools.kt index 9be6c39..02cd149 100644 --- a/app/src/main/java/top/fumiama/copymanga/net/DownloadTools.kt +++ b/app/src/main/java/top/fumiama/copymanga/net/DownloadTools.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.api.Config +import top.fumiama.copymanga.api.Config.proxyUrl import top.fumiama.copymanga.json.ComandyCapsule import top.fumiama.copymanga.lib.Comandy import java.io.ByteArrayOutputStream @@ -16,34 +17,40 @@ import java.io.OutputStream import java.lang.Thread.sleep import java.net.HttpURLConnection import java.net.URL +import java.text.SimpleDateFormat +import java.util.* import java.util.concurrent.Callable import java.util.concurrent.FutureTask import java.util.concurrent.atomic.AtomicInteger object DownloadTools { val failTimes = AtomicInteger(0) - fun getApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null, timeout: Int = 20000) = - url.let { - val connection = URL(url).openConnection() as HttpURLConnection - connection.requestMethod = method - connection.connectTimeout = timeout - connection.readTimeout = timeout - connection.apply { - setRequestProperty("host", url.substringAfter("://").substringBefore("/")) - ua?.let { setRequestProperty("user-agent", it) } - refer?.let { setRequestProperty("referer", it) } - setRequestProperty("source", "copyApp") - setRequestProperty("webp", "1") - setRequestProperty("region", if(!Config.net_use_foreign.value) "1" else "0") - setRequestProperty("version", Config.app_ver.value) - Config.token.value?.let { tk -> - setRequestProperty("authorization", "Token $tk") - } - setRequestProperty("platform", "3") + fun getApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null, timeout: Int = 20000): HttpURLConnection { + val connection = URL(url).openConnection() as HttpURLConnection + connection.requestMethod = method + connection.connectTimeout = timeout + connection.readTimeout = timeout + connection.apply { + /*setRequestProperty("host", if (url.startsWith("https://copymanga.azurewebsites.net")) { + Uri.parse(url).getQueryParameter("url")?.substringAfter("://")?.substringBefore("/")?:"" + } else { + url.substringAfter("://").substringBefore("/") + })*/ + ua?.let { setRequestProperty("user-agent", it) } + refer?.let { setRequestProperty("referer", it) } + setRequestProperty("source", "copyApp") + setRequestProperty("webp", "1") + setRequestProperty("region", if(!Config.net_use_foreign.value) "1" else "0") + setRequestProperty("version", Config.app_ver.value) + setRequestProperty("dt", SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()).format(Calendar.getInstance().time)) + Config.token.value?.let { tk -> + setRequestProperty("authorization", "Token $tk") } - Log.d("MyDT", "getConnection: $url\n${connection.requestProperties.map { "${it.key}: ${it.value}" }.joinToString("\n")}") - connection + setRequestProperty("platform", "3") } + Log.d("MyDT", "getConnection: $url\n${connection.requestProperties.map { "${it.key}: ${it.value}" }.joinToString("\n")}") + return connection + } fun getComandyApiConnection(url: String, method: String = "GET", refer: String? = null, ua: String? = null) = run { @@ -51,7 +58,11 @@ object DownloadTools { capsule.url = url capsule.method = method capsule.headers = hashMapOf() - capsule.headers["host"] = url.substringAfter("://").substringBefore("/") + /*capsule.headers["host"] = if (url.startsWith("https://copymanga.azurewebsites.net")) { + Uri.parse(url).getQueryParameter("url")?.substringAfter("://")?.substringBefore("/")?:"" + } else { + url.substringAfter("://").substringBefore("/") + }*/ ua?.let { capsule.headers["user-agent"] = it } refer?.let { capsule.headers["referer"] = it } capsule.headers["source"] = "copyApp" @@ -64,6 +75,7 @@ object DownloadTools { } } capsule.headers["platform"] = "3" + capsule.headers["dt"] = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()).format(Calendar.getInstance().time) Log.d("MyDT", "getComandyConnection: $url\n${capsule.headers.map { "${it.key}: ${it.value}" }.joinToString("\n")}") capsule } @@ -119,7 +131,7 @@ object DownloadTools { suspend fun getHttpContent(u: String, refer: String? = null, ua: String? = Config.pc_ua, p: Client.Progress? = null): ByteArray = withContext(Dispatchers.IO) { - if (!u.startsWith("https://copymanga.azurewebsites.net") && Comandy.instance.enabled) { + if (!u.startsWith("https://$proxyUrl") && Comandy.instance.enabled) { getComandyApiConnection(u, "GET", refer, ua).let { capsule -> val para = Gson().toJson(capsule) //Log.d("MyDT", "comandy request: $para") @@ -188,7 +200,7 @@ object DownloadTools { // prepare p only take effect when readSize is -1 fun prepare(u: String, readSize: Int = -1, p: Client.Progress? = null) = run { Log.d("MyDT", "prepareHttp: $u") - FutureTask(if (!u.startsWith("https://copymanga.azurewebsites.net") && Comandy.instance.enabled) Callable{ + FutureTask(if (!u.startsWith("https://$proxyUrl") && Comandy.instance.enabled) Callable{ try { runBlocking { Comandy.instance.getInstance() }?.let { ins -> runBlocking { @@ -261,7 +273,7 @@ object DownloadTools { fun requestWithBody(url: String, method: String, body: ByteArray, refer: String? = Config.referer, ua: String? = Config.pc_ua, contentType: String? = "application/x-www-form-urlencoded;charset=utf-8"): ByteArray? { Log.d("MyDT", "$method Http: $url") var ret: ByteArray? = null - val task = FutureTask(if(!url.startsWith("https://copymanga.azurewebsites.net") && Comandy.instance.enabled) Callable{ + val task = FutureTask(if(!url.startsWith("https://$proxyUrl") && Comandy.instance.enabled) Callable{ try { val capsule = getComandyApiConnection(url, method, refer, ua) contentType?.let { capsule.headers["content-type"] = it } diff --git a/app/src/main/java/top/fumiama/copymanga/net/Proxy.kt b/app/src/main/java/top/fumiama/copymanga/net/Proxy.kt index 102a1b6..fdf0447 100644 --- a/app/src/main/java/top/fumiama/copymanga/net/Proxy.kt +++ b/app/src/main/java/top/fumiama/copymanga/net/Proxy.kt @@ -44,6 +44,7 @@ class Proxy(id: Int, private val apiRegex: Regex) { ?:u Log.d("MyP", "[M] comancry: $wu, sd: $sourceDir") return use(wu)?.let { data -> + Log.d("MyP", "[M] comancry: decrypt ${data.size} bytes data") Comancry.instance.decrypt(sourceDir, data)?.encodeToByteArray() } } diff --git a/app/src/main/java/top/fumiama/copymanga/net/template/AutoDownloadHandler.kt b/app/src/main/java/top/fumiama/copymanga/net/template/AutoDownloadHandler.kt index cf566c5..50309c1 100644 --- a/app/src/main/java/top/fumiama/copymanga/net/template/AutoDownloadHandler.kt +++ b/app/src/main/java/top/fumiama/copymanga/net/template/AutoDownloadHandler.kt @@ -19,7 +19,7 @@ import java.io.File import java.security.MessageDigest open class AutoDownloadHandler( - private val url: String, private val jsonClass: Class<*>, + private val url: () -> String, private val jsonClass: Class<*>, private val context: LifecycleOwner?, private val loadFromCache: Boolean = false, private val customCacheFile: File? = null): Handler(Looper.myLooper()!!) { @@ -57,7 +57,7 @@ open class AutoDownloadHandler( toString() } private suspend fun downloadCoroutine() = withContext(Dispatchers.IO) { - val cacheName = toHexStr(MessageDigest.getInstance("MD5").digest(url.encodeToByteArray())) + val cacheName = toHexStr(MessageDigest.getInstance("MD5").digest(url().encodeToByteArray())) val cacheFile = customCacheFile?:(mainWeakReference?.get()?.externalCacheDir?.let { File(it, cacheName) }) if(loadFromCache) { cacheFile?.let { @@ -77,9 +77,9 @@ open class AutoDownloadHandler( var cnt = 0 while (cnt++ <= 3) { try { - val data = Config.apiProxy?.comancry(url) { + val data = Config.apiProxy?.comancry(url()) { DownloadTools.getHttpContent(it) - }?:DownloadTools.getHttpContent(url) + }?:DownloadTools.getHttpContent(url()) if(exit) return@withContext val fi = data.inputStream() val pass = setGsonItem(Gson().fromJson(fi.reader(), jsonClass)) diff --git a/app/src/main/java/top/fumiama/copymanga/storage/FileUtils.kt b/app/src/main/java/top/fumiama/copymanga/storage/FileUtils.kt index 109f8f4..6b7efcd 100644 --- a/app/src/main/java/top/fumiama/copymanga/storage/FileUtils.kt +++ b/app/src/main/java/top/fumiama/copymanga/storage/FileUtils.kt @@ -1,6 +1,15 @@ package top.fumiama.copymanga.storage +import android.content.Context +import android.net.Uri +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.fragment.app.Fragment +import java.io.BufferedOutputStream import java.io.File +import java.io.FileInputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream object FileUtils { fun recursiveRemove(f: File) { @@ -19,4 +28,52 @@ object FileUtils { } return size } + fun registerZipExportLauncher( + fragment: Fragment, + callback: (Uri?) -> Unit + ): ActivityResultLauncher { + return fragment.registerForActivityResult(ActivityResultContracts.CreateDocument("application/zip"), callback) + } + fun compressToUserFile( + context: Context, + sourceDir: File, + targetUri: Uri, + setProgress: (Int) -> Unit = {} + ) { + val allFiles = collectAllFiles(sourceDir) + val totalFiles = allFiles.size + var filesDone = 0 + + setProgress(0) // 确保初始进度为0% + + context.contentResolver.openOutputStream(targetUri)?.use { outputStream -> + ZipOutputStream(BufferedOutputStream(outputStream)).use { zipOut -> + for (file in allFiles) { + val relativePath = sourceDir.toURI().relativize(file.toURI()).path + val entry = ZipEntry(relativePath) + zipOut.putNextEntry(entry) + + FileInputStream(file).use { input -> + input.copyTo(zipOut) + } + + zipOut.closeEntry() + filesDone++ + val progress = (filesDone * 100 / totalFiles).coerceIn(0, 100) + setProgress(progress) + } + } + } + + setProgress(100) // 确保最终进度为100% + } + + private fun collectAllFiles(root: File): List { + val files = mutableListOf() + root.walkTopDown().forEach { + if (it.isFile) files.add(it) + } + return files + } + } \ No newline at end of file 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 38c94eb..e109bc7 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 @@ -140,17 +140,11 @@ class BookFragment: NoBackRefreshFragment(R.layout.fragment_book) { fun setReadTo() { var chapter = "未读" if(!mBookHandler?.chapterNames.isNullOrEmpty()) { - activity?.apply { + chapter = "读至 ${activity?.let { a -> 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] - } - } - } - } + Reader.getLocalReadingProgress(a, name, mBookHandler!!.chapterNames) + } }}" } - chapter = "读至 $chapter" this@BookFragment.bttag.text = chapter } 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 73de754..0687380 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 @@ -218,13 +218,16 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m } var last = i-1 val comicName = name?:return@withContext + val init = i + Log.d("MyBH", "i = $i, last=$last, add comic $comicName, volume $p") volumes[p].let { v -> if(exit) return@withContext var line: View? = null last += v.results.list.size - v.results.list.forEach { + val inv = Config.view_manga_inverse_chapters.value + (if(!inv) v.results.list.toList() else v.results.list.reversed()).forEach { val f = Config.getZipFile(context?.getExternalFilesDir(""), comicName, keys[p], it.name) - //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) delay(500) if (exit) return@withContext @@ -236,7 +239,7 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m lct.text = it.name if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) Log.d("MyBH", "add last single chapter ${it.name}") - val index = i + val index = if (!inv) i else init setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } } line?.let { l -> addVolumesView(fbl, l) } @@ -245,14 +248,14 @@ class BookHandler(private val th: WeakReference): Handler(Looper.m line?.l2cl?.apply { lct.text = it.name if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) - val index = i + val index = if (!inv) i else (init+last-i) setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } } } } else line?.l2cr?.apply { lct.text = it.name if (f.exists()) lci.setBackgroundResource(R.drawable.ic_success) - val index = i + val index = if (!inv) i else (init+last-i) setOnClickListener { Reader.start2viewManga(comicName, index, urlArray, uuidArray) } line?.let { l -> addVolumesView(fbl, l) } line = null diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/history/HistoryFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/history/HistoryFragment.kt index be5c8cc..31c2c29 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/history/HistoryFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/history/HistoryFragment.kt @@ -11,7 +11,7 @@ import top.fumiama.dmzj.copymanga.R @OptIn(ExperimentalStdlibApi::class) class HistoryFragment : InfoCardLoader(R.layout.fragment_history, R.id.action_nav_history_to_nav_book, isHistoryBook = true) { override fun getApiUrl() = - getString(R.string.historyApiUrl).format(Config.myHostApiUrl.value, page * 21) + getString(R.string.historyApiUrl).format(Config.myHostApiUrl.random(), page * 21) override fun onCreate(savedInstanceState: Bundle?) { if (MainActivity.member?.hasLogin != true) { diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt index e8bea70..5ec5b00 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/newest/NewestFragment.kt @@ -7,5 +7,5 @@ import top.fumiama.dmzj.copymanga.R @ExperimentalStdlibApi class NewestFragment : InfoCardLoader(R.layout.fragment_newest, R.id.action_nav_newest_to_nav_book, true) { override fun getApiUrl() = - getString(R.string.newestApiUrl).format(Config.myHostApiUrl.value, page * 21) + getString(R.string.newestApiUrl).format(Config.myHostApiUrl.random(), page * 21) } diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt index f6dae93..f7e4f41 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/rank/RankFragment.kt @@ -48,7 +48,7 @@ class RankFragment : InfoCardLoader(R.layout.fragment_rank, R.id.action_nav_rank override fun getApiUrl() = getString(R.string.rankApiUrl).format( - Config.myHostApiUrl.value, + Config.myHostApiUrl.random(), page * 21, sortWay[sortValue], audienceWay[audience] diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/recommend/RecFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/recommend/RecFragment.kt index 527ed02..0461a84 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/recommend/RecFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/recommend/RecFragment.kt @@ -7,5 +7,5 @@ import top.fumiama.dmzj.copymanga.R @ExperimentalStdlibApi class RecFragment : InfoCardLoader(R.layout.fragment_recommend, R.id.action_nav_recommend_to_nav_book, true) { override fun getApiUrl() = - getString(R.string.recommendApiUrl).format(Config.myHostApiUrl.value, page * 21) + getString(R.string.recommendApiUrl).format(Config.myHostApiUrl.random(), page * 21) } \ No newline at end of file diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/search/SearchFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/search/SearchFragment.kt index fc9ed73..835a5b4 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/search/SearchFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/search/SearchFragment.kt @@ -13,7 +13,7 @@ class SearchFragment : InfoCardLoader(R.layout.fragment_search, R.id.action_nav_ private var query: String? = null private var type: String? = null override fun getApiUrl() = - getString(R.string.searchApiUrl).format(Config.myHostApiUrl.value, page * 21, query, type) + getString(R.string.searchApiUrl).format(Config.myHostApiUrl.random(), page * 21, query, type) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt index 832bda2..e253d93 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/shelf/ShelfFragment.kt @@ -26,7 +26,7 @@ class ShelfFragment : InfoCardLoader(R.layout.fragment_shelf, R.id.action_nav_su override fun getApiUrl() = getString(R.string.shelfApiUrl).format( - Config.myHostApiUrl.value, + Config.myHostApiUrl.random(), page * 21, sortWay[sortValue] ) diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt index 374a7b7..fae8ecd 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/sort/SortFragment.kt @@ -25,7 +25,7 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou override fun getApiUrl() = getString(R.string.sortApiUrl).format( - Config.myHostApiUrl.value, + Config.myHostApiUrl.random(), page * 21, sortWay[sortValue], if(theme >= 0 && theme < (filter?.results?.theme?.size ?: 0)) (filter?.results?.theme?.get(theme)?.path_word ?: "") else "", @@ -42,7 +42,7 @@ class SortFragment : StatusCardFlow(0, R.id.action_nav_sort_to_nav_book, R.layou super.setListeners() lifecycleScope.launch { setProgress(5) - PausableDownloader(getString(R.string.filterApiUrl).format(Config.myHostApiUrl.value)) { + PausableDownloader(getString(R.string.filterApiUrl).format(Config.myHostApiUrl.random())) { if(ad?.exit == true) return@PausableDownloader it.let { it.inputStream().use { i -> diff --git a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt index abd6b50..3117f11 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/cardflow/topic/TopicFragment.kt @@ -18,13 +18,13 @@ import top.fumiama.dmzj.copymanga.R class TopicFragment : InfoCardLoader(R.layout.fragment_topic, R.id.action_nav_topic_to_nav_book) { private var type = 1 override fun getApiUrl() = - getString(R.string.topicContentApiUrl).format(Config.myHostApiUrl.value, arguments?.getString("path"), type, offset) + getString(R.string.topicContentApiUrl).format(Config.myHostApiUrl.random(), arguments?.getString("path"), type, offset) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { setProgress(5) - PausableDownloader(getString(R.string.topicApiUrl).format(Config.myHostApiUrl.value, arguments?.getString("path"))) { data -> + PausableDownloader(getString(R.string.topicApiUrl).format(Config.myHostApiUrl.random(), arguments?.getString("path"))) { data -> setProgress(10) withContext(Dispatchers.IO) { if(ad?.exit == true) return@withContext diff --git a/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt index 9120f7d..3a9a2da 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/download/NewDownloadFragment.kt @@ -1,25 +1,33 @@ package top.fumiama.copymanga.ui.download +import android.annotation.SuppressLint import android.app.AlertDialog import android.os.Bundle import android.util.Log import android.view.View +import androidx.activity.result.ActivityResultLauncher +import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import kotlinx.android.synthetic.main.dialog_progress.view.* +import kotlinx.android.synthetic.main.line_header.view.* +import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import top.fumiama.copymanga.MainActivity.Companion.mainWeakReference +import top.fumiama.copymanga.MainActivity import top.fumiama.copymanga.api.Config.manga_dl_show_0m_manga import top.fumiama.copymanga.api.manga.Downloader import top.fumiama.copymanga.api.manga.Reader -import top.fumiama.copymanga.view.template.MangaPagesFragmentTemplate -import top.fumiama.copymanga.view.template.CardList +import top.fumiama.copymanga.net.Client import top.fumiama.copymanga.storage.FileUtils +import top.fumiama.copymanga.storage.FileUtils.compressToUserFile import top.fumiama.copymanga.view.interaction.Navigate import top.fumiama.copymanga.view.interaction.UITools +import top.fumiama.copymanga.view.template.CardList +import top.fumiama.copymanga.view.template.MangaPagesFragmentTemplate import top.fumiama.dmzj.copymanga.R import java.io.File import java.lang.ref.WeakReference @@ -27,25 +35,48 @@ import java.lang.ref.WeakReference @OptIn(ExperimentalStdlibApi::class) class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownload, forceLoad = true) { private var sortedBookList: List? = null - private val oldDlCardName = mainWeakReference?.get()?.getString(R.string.old_download_card_name)!! - private val extDir = mainWeakReference?.get()?.getExternalFilesDir("") + private val oldDlCardName by lazy { getString(R.string.old_download_card_name) } + private val extDir by lazy { activity?.getExternalFilesDir("") } private var isReverse = false private var isContentChanged = false private var exit = false private val showAll get() = manga_dl_show_0m_manga.value + private var compressIntoFile: ActivityResultLauncher? = null + private var compressName = "" + private var compressFile: File? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) wn = WeakReference(this) + + compressIntoFile = FileUtils.registerZipExportLauncher(this@NewDownloadFragment) { uri -> + val progressBar = layoutInflater.inflate(R.layout.dialog_progress, null, false) + val progressHandler = object : Client.Progress{ + override fun notify(progressPercentage: Int) { + progressBar?.dpp?.progress = progressPercentage + } + } + val info = (activity as MainActivity).toolsBox.buildAlertWithView("压缩${compressName}.zip", progressBar!!, "隐藏") + val f = compressFile!! + Thread{ + uri?.let { context?.let { ctx -> compressToUserFile(ctx, f, it) { + progressHandler.notify(it) + if (it >= 100) activity?.runOnUiThread { info.dismiss() } + } } } + }.start() + } } override fun onPause() { super.onPause() exit = true + wn = null } override fun onResume() { super.onResume() exit = false + wn = WeakReference(this) } override fun onDestroy() { @@ -54,6 +85,7 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl exit = true } + @SuppressLint("SetTextI18n") override suspend fun addPage(): Unit = withContext(Dispatchers.IO) { super.addPage() if(isRefresh) { @@ -105,8 +137,18 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl cnt = 1 } val size = sortedBookList?.size?:0 - sortedBookList?.let { - for(i in it.listIterator(page)) { + sortedBookList?.let { lst -> + withContext(Dispatchers.Main) { + mysp?.footerView?.lht?.text = "$page+" + activity?.findViewById(R.id.toolbar)?.let { appbar -> + appbar.title.let { title -> + if (!title.endsWith(")")) { + appbar.title = "$title (${lst.size})" + } + } + } + } + for(i in lst.listIterator(page)) { if(cardList?.exitCardList != false) return@withContext page++ // page is actually count val chosenJson = File(i, "info.bin") @@ -120,14 +162,16 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl chosenJson.exists() -> continue // unsupported old folder newJson.exists() -> { if(cardList?.exitCardList != false) return@withContext - cardList?.addCard(i.name, bookSize) + cardList?.addCard(i.name, "\n本地读至 ${activity?.let { a -> + Reader.getLocalReadingProgress(a, i.name, Reader.getComicChapterNamesInFolder(i)) + }}$bookSize") cnt++ } } setProgress(80+20*(cnt-1)/size) if (cnt >= 21) break } - if(page >= it.size) { + if(page >= lst.size) { isEnd = true } } @@ -155,7 +199,7 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl AlertDialog.Builder(context) .setIcon(R.drawable.ic_launcher_foreground) .setTitle(R.string.new_download_card_option_hint) - .setItems(arrayOf("删除数据文件夹", "直接前往下载页")) { d, p -> + .setItems(arrayOf("删除数据文件夹", "直接前往下载页", "导出压缩包")) { d, p -> d.cancel() when (p) { 0 -> { @@ -174,10 +218,14 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl .show() } 1 -> callDownloadFragment(name) + 2 -> { + compressName = name + compressFile = chosenFile + compressIntoFile?.launch("${name}.zip") + } } } .show() - true } } @@ -220,6 +268,10 @@ class NewDownloadFragment: MangaPagesFragmentTemplate(R.layout.fragment_newdownl ) } + fun importMangaFromZip() { + + } + companion object { var wn: WeakReference? = null } 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 6347ec3..956d7b1 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 @@ -298,7 +298,7 @@ class HomeFragment : NoBackRefreshFragment(R.layout.fragment_home) { suspend fun refresh(q: CharSequence) = withContext(Dispatchers.IO) { query = q.toString() activity?.apply { - PausableDownloader(getString(R.string.searchApiUrl).format(Config.myHostApiUrl.value, 0, + PausableDownloader(getString(R.string.searchApiUrl).format(Config.myHostApiUrl.random(), 0, URLEncoder.encode(q.toString(), Charset.defaultCharset().name()), type)) { results = Gson().fromJson(it.decodeToString(), BookListStructure::class.java) count = results?.results?.total?:0 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 c4c0494..a2e6b92 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 @@ -39,8 +39,9 @@ import top.fumiama.dmzj.copymanga.R import java.lang.ref.WeakReference import java.util.concurrent.atomic.AtomicInteger -class HomeHandler(private val that: WeakReference) : AutoDownloadHandler( - that.get()?.getString(R.string.mainPageApiUrl)!!.format(Config.myHostApiUrl.value), +class HomeHandler(private val that: WeakReference) : AutoDownloadHandler({ + that.get()?.getString(R.string.mainPageApiUrl)!!.format(Config.myHostApiUrl.random()) + }, IndexStructure::class.java, that.get() ) { diff --git a/app/src/main/java/top/fumiama/copymanga/ui/settings/SettingsFragment.kt b/app/src/main/java/top/fumiama/copymanga/ui/settings/SettingsFragment.kt index b4e18e9..827c3b7 100644 --- a/app/src/main/java/top/fumiama/copymanga/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/top/fumiama/copymanga/ui/settings/SettingsFragment.kt @@ -3,14 +3,19 @@ package top.fumiama.copymanga.ui.settings import android.os.Bundle import android.util.Log import android.view.View +import androidx.appcompat.app.AppCompatDelegate import androidx.lifecycle.lifecycleScope import androidx.preference.EditTextPreference +import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import androidx.preference.SwitchPreferenceCompat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import top.fumiama.copymanga.api.Config.proxyUrl import top.fumiama.copymanga.view.interaction.UITools import top.fumiama.copymanga.view.AutoHideEditTextPreferenceDialogFragmentCompat import top.fumiama.dmzj.copymanga.R @@ -22,6 +27,21 @@ class SettingsFragment: PreferenceFragmentCompat() { delay(300) withContext(Dispatchers.Main) { setPreferencesFromResource(R.xml.pref_setting, rootKey) + findPreference(getString(R.string.darkModeKeyID))?.setOnPreferenceChangeListener { _, newValue -> + when ((newValue as String).toInt()) { + 0 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) + 1 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + 2 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + } + true // 允许保存新值 + } + context?.let { PreferenceManager.getDefaultSharedPreferences(it) }?.let { + if (it.getString(getString(R.string.reverseProxyKeyID), "") != proxyUrl) { + findPreference(getString(R.string.apiProxyKeyID))?.isVisible = false + findPreference(getString(R.string.imgProxyKeyID))?.isVisible = false + findPreference(getString(R.string.imgProxyCodeKeyID))?.isVisible = false + } + } } } } 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 38909d1..2101100 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 @@ -30,7 +30,7 @@ import java.text.SimpleDateFormat import java.util.* class VMHandler(activity: ViewMangaActivity, private val chapterUrl: String, private val weeks: Array) : AutoDownloadHandler( - chapterUrl, Chapter2Return::class.java, activity + { chapterUrl }, Chapter2Return::class.java, activity ) { var manga: Chapter2Return? = null private val wv = WeakReference(activity) diff --git a/app/src/main/java/top/fumiama/copymanga/view/template/InfoCardLoader.kt b/app/src/main/java/top/fumiama/copymanga/view/template/InfoCardLoader.kt index 0ca63b2..603b062 100644 --- a/app/src/main/java/top/fumiama/copymanga/view/template/InfoCardLoader.kt +++ b/app/src/main/java/top/fumiama/copymanga/view/template/InfoCardLoader.kt @@ -1,12 +1,16 @@ package top.fumiama.copymanga.view.template +import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import android.view.View +import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.gson.Gson +import kotlinx.android.synthetic.main.line_header.view.* +import kotlinx.android.synthetic.main.line_lazybooklines.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -18,6 +22,7 @@ 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 top.fumiama.dmzj.copymanga.R import java.lang.ref.WeakReference @ExperimentalStdlibApi @@ -26,6 +31,7 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT private val subUrl get() = getApiUrl() var ad: PausableDownloader? = null + @SuppressLint("SetTextI18n") override suspend fun addPage(): Unit = withContext(Dispatchers.IO) { super.addPage() setProgress(20) @@ -38,6 +44,16 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT val bookList = Gson().fromJson(data.decodeToString(), TypeBookListStructure::class.java) bookList?.apply { Log.d("MyICL", "offset:${results.offset}, total:${results.total}") + withContext(Dispatchers.Main) { + mysp?.footerView?.lht?.text = "${results.offset}+" + activity?.findViewById(R.id.toolbar)?.let { appbar -> + appbar.title.let { + if (!it.endsWith(")")) { + appbar.title = "$it (${results.total})" + } + } + } + } if(results.offset < results.total) { if(code == 200) { val size = results?.list?.size?:0 @@ -60,6 +76,16 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT val bookList = Gson().fromJson(data.decodeToString(), HistoryBookListStructure::class.java) bookList?.apply { Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") + withContext(Dispatchers.Main) { + mysp?.footerView?.lht?.text = "${results.offset}+" + activity?.findViewById(R.id.toolbar)?.let { appbar -> + appbar.title.let { + if (!it.endsWith(")")) { + appbar.title = "$it (${results.total})" + } + } + } + } if(results.offset < results.total) { if(code == 200) { val size = results?.list?.size?:0 @@ -82,6 +108,16 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT val bookList = Gson().fromJson(data.decodeToString(), ShelfStructure::class.java) bookList?.apply { Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") + withContext(Dispatchers.Main) { + mysp?.footerView?.lht?.text = "${results.offset}+" + activity?.findViewById(R.id.toolbar)?.let { appbar -> + appbar.title.let { + if (!it.endsWith(")")) { + appbar.title = "$it (${results.total})" + } + } + } + } if(results.offset < results.total) { if(code == 200) { val size = results?.list?.size?:0 @@ -105,6 +141,16 @@ open class InfoCardLoader(inflateRes:Int, private val navId:Int, private val isT val bookList = Gson().fromJson(data.decodeToString(), BookListStructure::class.java) bookList?.apply { Log.d("MyICL", "offset:${results?.offset}, total:${results?.total}") + withContext(Dispatchers.Main) { + mysp?.footerView?.lht?.text = "${results.offset}+" + activity?.findViewById(R.id.toolbar)?.let { appbar -> + appbar.title.let { + if (!it.endsWith(")")) { + appbar.title = "$it (${results.total})" + } + } + } + } if(results.offset < results.total) { if(code == 200) { val size = results?.list?.size?:0 diff --git a/app/src/main/java/top/fumiama/copymanga/view/template/StatusCardFlow.kt b/app/src/main/java/top/fumiama/copymanga/view/template/StatusCardFlow.kt index 162d602..3f3c999 100644 --- a/app/src/main/java/top/fumiama/copymanga/view/template/StatusCardFlow.kt +++ b/app/src/main/java/top/fumiama/copymanga/view/template/StatusCardFlow.kt @@ -18,7 +18,7 @@ open class StatusCardFlow(private val api: Int, nav: Int, inflateRes: Int, override fun getApiUrl() = getString(api).format( - Config.myHostApiUrl.value, + Config.myHostApiUrl.random(), page * 21, sortWay[sortValue] ) diff --git a/app/src/main/java/top/fumiama/copymanga/view/template/ThemeCardFlow.kt b/app/src/main/java/top/fumiama/copymanga/view/template/ThemeCardFlow.kt index a739699..7483218 100644 --- a/app/src/main/java/top/fumiama/copymanga/view/template/ThemeCardFlow.kt +++ b/app/src/main/java/top/fumiama/copymanga/view/template/ThemeCardFlow.kt @@ -12,7 +12,7 @@ open class ThemeCardFlow(private val api: Int, nav: Int) : StatusCardFlow(0, nav private var theme = "" override fun getApiUrl() = getString(api).format( - Config.myHostApiUrl.value, + Config.myHostApiUrl.random(), page * 21, sortWay[sortValue], theme diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 9bae08e..5411756 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -38,4 +38,14 @@ 5 6 + + 跟随系统 + 浅色 + 深色 + + + 0 + 1 + 2 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d3ee1d6..fbd80ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,8 @@ - + + + ]> 拷贝漫画 @@ -66,6 +67,7 @@ https://%1$s/api/v3/h5/homeIndex?platform=3 https://%1$s &hosturl; + &proxyurl; https://%1$s/api/v3/ranks?limit=21&offset=%2$d&date_type=%3$s&audience_type=%4$s&platform=3 https://%1$s/api/v3/search/comic?limit=21&offset=%2$d&q=%3$s&q_type=%4$s&platform=3 https://%1$s/api/v3/h5/filter/comic/tags?platform=3 @@ -87,11 +89,16 @@ https://%1$s/api/v3/member/collect/comics?limit=21&offset=%2$d&free_type=1&ordering=%3$s&platform=3 https://%1$s/api/v3/member/collect/comic - https://copymanga.azurewebsites.net/api/img?code=%1$s&url=%2$s - settings_cat_net_et_img_proxy_code - https://copymanga.azurewebsites.net/api/api?code=%1$s&url=%2$s + https://&proxyurl;/api/img?code=%1$s&url=%2$s + settings_cat_net_et_img_proxy_code + https://&proxyurl;/api/api?code=%1$s&url=%2$s settings_cat_net_sb_image_resolution + settings_cat_general_lp_dark_mode + settings_cat_net_et_reverse_proxy + settings_cat_net_sw_use_api_proxy + settings_cat_net_sw_use_img_proxy + https://gitea.seku.su/api/v1/repos/fumiama/%1$s/releases/tags/default "https://gitea.seku.su/fumiama/%1$s/releases/download/default/%2$s_%3$s.gz" @@ -141,6 +148,8 @@ 标签 通用 + 主题 + 默认跟随系统 启动时显示 默认主页 拷贝版本号 @@ -163,14 +172,18 @@ 使用经过优化的请求方法访问服务器 请求API网址 一般无需更改,除非拷贝漫画官方更改网址,默认:&hosturl; + 反向代理 + 您可以自建反向代理并填写在此处以解决网络不畅 使用API代理(需要密钥) 作者自建的API代理,可缓解国内图书详情加载问题,但不保证100%解决,也不保证一直可用 使用图床代理(需要密钥) 作者自建的图床代理,可缓解国内图片无法加载问题,但不保证100%解决,也不保证一直可用 代理密钥 - 为避免滥用,该密钥需加群(559748702)获得,且随时可能会刷新 + 为避免滥用,该密钥随时可能会刷新 漫画浏览 + 倒序排列章节 + 打开后详情页将从后往前排列每一话 深色阅读背景 打开后阅览漫画的背景色永远为黑色 隐藏底部时间栏 diff --git a/app/src/main/res/xml/pref_setting.xml b/app/src/main/res/xml/pref_setting.xml index 7dd6c98..835fa48 100644 --- a/app/src/main/res/xml/pref_setting.xml +++ b/app/src/main/res/xml/pref_setting.xml @@ -4,6 +4,16 @@ + + @@ -110,11 +130,17 @@ android:summary="@string/settings_cat_net_et_summary_img_proxy" app:enableCopying="true" app:iconSpaceReserved="false" - app:key="settings_cat_net_et_img_proxy_code" /> + app:key="@string/imgProxyCodeKeyID" /> +