适配新api

pull/21/head
fengyuecanzhu 3 years ago
parent 55da055e83
commit ef475af436
  1. 2
      app/build.gradle
  2. 365
      app/src/main/java/xyz/fycz/myreader/model/JSExtensions.kt
  3. 34
      app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt
  4. 15
      app/src/main/java/xyz/fycz/myreader/util/webdav/WebDav.kt
  5. 2
      app/src/main/java/xyz/fycz/myreader/widget/CircleCheckBox.java
  6. 8
      app/src/main/res/values/strings.xml
  7. 2
      app/src/main/res/values/styles.xml

@ -152,7 +152,7 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.6.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'

@ -1,365 +0,0 @@
package xyz.fycz.myreader.util.help
import android.util.Base64
import android.util.Log
import androidx.annotation.Keep
import org.jsoup.Connection
import org.jsoup.Jsoup
import xyz.fycz.myreader.greendao.service.CookieStore
import xyz.fycz.myreader.model.third2.analyzeRule.AnalyzeUrl
import xyz.fycz.myreader.util.ZipUtils
import xyz.fycz.myreader.util.utils.*
import java.io.File
import java.io.IOException
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.*
/**
* @author fengyue
* @date 2021/5/15 19:26
*/
@Keep
@Suppress("unused")
interface JSExtensions {
/**
* js实现跨域访问,不能删
*/
fun ajax(urlStr: String?): String? {
return try {
val analyzeUrl = AnalyzeUrl(urlStr)
OkHttpUtils.getStrResponse(analyzeUrl).blockingFirst().body()
} catch (e: Exception) {
e.localizedMessage
}
}
/**
* js实现压缩文件解压
*/
fun unzipFile(zipPath: String): String {
if (zipPath.isEmpty()) return ""
val unzipPath = FileUtils.getCachePath() + File.separator + FileUtils.getNameExcludeExtension(zipPath)
FileUtils.deleteFile(unzipPath)
val zipFile = FileUtils.getFile(zipPath)
val unzipFolder = FileUtils.getFolder(unzipPath)
ZipUtils.unzipFile(zipFile, unzipFolder)
FileUtils.deleteFile(zipPath)
return unzipPath
}
/**
* js实现文件夹内所有文件读取
*/
fun getTxtInFolder(unzipPath: String): String {
if (unzipPath.isEmpty()) return ""
val unzipFolder = FileUtils.getFolder(unzipPath)
val contents = StringBuilder()
unzipFolder.listFiles().let {
if (it != null) {
for (f in it) {
val charsetName = FileUtils.getFileCharset(f)
contents.append(String(f.readBytes(), charset(charsetName)))
.append("\n")
}
contents.deleteCharAt(contents.length - 1)
}
}
FileUtils.deleteFile(unzipPath)
return contents.toString()
}
/**
* js实现重定向拦截,不能删
*/
@Throws(IOException::class)
operator fun get(urlStr: String?, headers: Map<String?, String?>?): Connection.Response? {
return Jsoup.connect(urlStr)
.sslSocketFactory(SSLSocketClient.createSSLSocketFactory())
.ignoreContentType(true)
.followRedirects(false)
.headers(headers)
.method(Connection.Method.GET)
.execute()
}
/**
* js实现重定向拦截,不能删
*/
@Throws(IOException::class)
fun post(
urlStr: String?,
body: String?,
headers: Map<String?, String?>?
): Connection.Response? {
return Jsoup.connect(urlStr)
.sslSocketFactory(SSLSocketClient.createSSLSocketFactory())
.ignoreContentType(true)
.followRedirects(false)
.requestBody(body)
.headers(headers)
.method(Connection.Method.POST)
.execute()
}
/**
*js实现读取cookie
*/
fun getCookie(tag: String, key: String? = null): String {
val cookie = CookieStore.getCookie(tag)
val cookieMap = CookieStore.cookieToMap(cookie)
return if (key != null) {
cookieMap[key] ?: ""
} else {
cookie
}
}
/**
* js实现解码,不能删
*/
fun base64Decode(str: String): String {
return EncoderUtils.base64Decode(str, Base64.NO_WRAP)
}
fun base64Decode(str: String, flags: Int): String {
return EncoderUtils.base64Decode(str, flags)
}
fun base64DecodeToByteArray(str: String?): ByteArray? {
if (str.isNullOrBlank()) {
return null
}
return Base64.decode(str, Base64.DEFAULT)
}
fun base64DecodeToByteArray(str: String?, flags: Int): ByteArray? {
if (str.isNullOrBlank()) {
return null
}
return Base64.decode(str, flags)
}
fun base64Encode(str: String): String? {
return EncoderUtils.base64Encode(str, Base64.NO_WRAP)
}
fun base64Encode(str: String, flags: Int): String? {
return EncoderUtils.base64Encode(str, flags)
}
fun md5Encode(str: String): String {
return MD5Utils.md5Encode(str)
}
fun md5Encode16(str: String): String {
return MD5Utils.md5Encode16(str)
}
/**
* 时间格式化
*/
fun timeFormat(time: Long): String {
val sdf = SimpleDateFormat("yyyy/MM/dd HH:mm")
return sdf.format(Date(time))
}
/**
* utf8编码转gbk编码
*/
fun utf8ToGbk(str: String): String {
val utf8 = String(str.toByteArray(charset("UTF-8")))
val unicode = String(utf8.toByteArray(), charset("UTF-8"))
return String(unicode.toByteArray(charset("GBK")))
}
fun encodeURI(str: String): String {
return try {
URLEncoder.encode(str, "UTF-8")
} catch (e: Exception) {
""
}
}
fun encodeURI(str: String, enc: String): String {
return try {
URLEncoder.encode(str, enc)
} catch (e: Exception) {
""
}
}
fun htmlFormat(str: String): String {
return StringUtils.formatHtml(str)
}
/**
* 读取本地文件
*/
fun readFile(path: String): ByteArray {
return File(path).readBytes()
}
fun readTxtFile(path: String): String {
val f = File(path)
val charsetName = FileUtils.getFileCharset(f)
return String(f.readBytes(), charset(charsetName))
}
fun readTxtFile(path: String, charsetName: String): String {
return String(File(path).readBytes(), charset(charsetName))
}
/**
* 输出调试日志
*/
fun log(msg: String): String {
Log.d("JS", msg)
return msg
}
/**
* AES 解码为 ByteArray
* @param str 传入的AES加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesDecodeToByteArray(
str: String,
key: String,
transformation: String,
iv: String = ""
): ByteArray? {
return EncoderUtils.decryptAES(
data = str.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
}
/**
* AES 解码为 String
* @param str 传入的AES加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesDecodeToString(
str: String,
key: String,
transformation: String,
iv: String = ""
): String? {
return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
}
/**
* 已经base64的AES 解码为 ByteArray
* @param str 传入的AES Base64加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesBase64DecodeToByteArray(
str: String,
key: String,
transformation: String,
iv: String = ""
): ByteArray? {
return EncoderUtils.decryptBase64AES(
data = str.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
}
/**
* 已经base64的AES 解码为 String
* @param str 传入的AES Base64加密的数据
* @param key AES 解密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesBase64DecodeToString(
str: String,
key: String,
transformation: String,
iv: String = ""
): String? {
return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
}
/**
* 加密aes为ByteArray
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToByteArray(
data: String, key: String, transformation: String,
iv: String = ""
): ByteArray? {
return EncoderUtils.encryptAES(
data.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
}
/**
* 加密aes为String
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToString(
data: String, key: String, transformation: String,
iv: String = ""
): String? {
return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) }
}
/**
* 加密aes后Base64化的ByteArray
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToBase64ByteArray(
data: String, key: String, transformation: String,
iv: String = ""
): ByteArray? {
return EncoderUtils.encryptAES2Base64(
data.encodeToByteArray(),
key = key.encodeToByteArray(),
transformation,
iv.encodeToByteArray()
)
}
/**
* 加密aes后Base64化的String
* @param data 传入的原始数据
* @param key AES加密的key
* @param transformation AES加密的方式
* @param iv ECB模式的偏移向量
*/
fun aesEncodeToBase64String(
data: String, key: String, transformation: String,
iv: String = ""
): String? {
return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) }
}
}

@ -5,8 +5,10 @@ import io.reactivex.SingleOnSubscribe
import io.reactivex.SingleSource import io.reactivex.SingleSource
import io.reactivex.functions.Function import io.reactivex.functions.Function
import net.lingala.zip4j.ZipFile import net.lingala.zip4j.ZipFile
import okhttp3.MediaType import net.lingala.zip4j.model.ZipParameters
import okhttp3.RequestBody import net.lingala.zip4j.model.enums.EncryptionMethod
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import xyz.fycz.myreader.application.App import xyz.fycz.myreader.application.App
import xyz.fycz.myreader.common.APPCONST import xyz.fycz.myreader.common.APPCONST
import xyz.fycz.myreader.common.URLCONST import xyz.fycz.myreader.common.URLCONST
@ -19,10 +21,6 @@ import xyz.fycz.myreader.util.utils.GSON
import xyz.fycz.myreader.util.utils.OkHttpUtils import xyz.fycz.myreader.util.utils.OkHttpUtils
import xyz.fycz.myreader.util.utils.RxUtils import xyz.fycz.myreader.util.utils.RxUtils
import java.io.File import java.io.File
import net.lingala.zip4j.model.enums.EncryptionMethod
import net.lingala.zip4j.model.ZipParameters
import xyz.fycz.myreader.base.observer.MySingleObserver
/** /**
* @author fengyue * @author fengyue
@ -32,11 +30,11 @@ object UserService2 {
fun login(user: User): Single<Result> { fun login(user: User): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "username=${user.userName}" + val body = "username=${user.userName}" +
"&password=${user.password}" + "&password=${user.password}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/login", requestBody, "UTF-8") val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/login", requestBody, "UTF-8")
it.onSuccess(GSON.fromJson(ret, Result::class.java)) it.onSuccess(GSON.fromJson(ret, Result::class.java))
}).compose { RxUtils.toSimpleSingle(it) } }).compose { RxUtils.toSimpleSingle(it) }
@ -44,7 +42,7 @@ object UserService2 {
fun register(user: User, code: String, keyc: String): Single<Result> { fun register(user: User, code: String, keyc: String): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "username=${user.userName}" + val body = "username=${user.userName}" +
"&password=${user.password}" + "&password=${user.password}" +
"&email=${user.email}" + "&email=${user.email}" +
@ -52,7 +50,7 @@ object UserService2 {
"&keyc=${keyc}" + "&keyc=${keyc}" +
"&key=${CyptoUtils.encode(APPCONST.KEY, APPCONST.publicKey)}" + "&key=${CyptoUtils.encode(APPCONST.KEY, APPCONST.publicKey)}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/reg", requestBody, "UTF-8") val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/reg", requestBody, "UTF-8")
it.onSuccess(GSON.fromJson(ret, Result::class.java)) it.onSuccess(GSON.fromJson(ret, Result::class.java))
}).compose { RxUtils.toSimpleSingle(it) } }).compose { RxUtils.toSimpleSingle(it) }
@ -60,13 +58,13 @@ object UserService2 {
fun bindEmail(user: User, code: String, keyc: String): Single<Result> { fun bindEmail(user: User, code: String, keyc: String): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "username=${user.userName}" + val body = "username=${user.userName}" +
"&email=${user.email}" + "&email=${user.email}" +
"&code=${code}" + "&code=${code}" +
"&keyc=${keyc}" + "&keyc=${keyc}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/bindEmail", requestBody, "UTF-8") val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/bindEmail", requestBody, "UTF-8")
it.onSuccess(GSON.fromJson(ret, Result::class.java)) it.onSuccess(GSON.fromJson(ret, Result::class.java))
}).compose { RxUtils.toSimpleSingle(it) } }).compose { RxUtils.toSimpleSingle(it) }
@ -74,13 +72,13 @@ object UserService2 {
fun resetPwd(user: User, code: String, keyc: String): Single<Result> { fun resetPwd(user: User, code: String, keyc: String): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "email=${user.email}" + val body = "email=${user.email}" +
"&password=${user.password}" + "&password=${user.password}" +
"&code=${code}" + "&code=${code}" +
"&keyc=${keyc}" + "&keyc=${keyc}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/resetPwd", requestBody, "UTF-8") val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/resetPwd", requestBody, "UTF-8")
it.onSuccess(GSON.fromJson(ret, Result::class.java)) it.onSuccess(GSON.fromJson(ret, Result::class.java))
}).compose { RxUtils.toSimpleSingle(it) } }).compose { RxUtils.toSimpleSingle(it) }
@ -88,12 +86,12 @@ object UserService2 {
fun sendEmail(email: String, type: String, keyc: String = ""): Single<Result> { fun sendEmail(email: String, type: String, keyc: String = ""): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "email=${email}" + val body = "email=${email}" +
"&type=${type}" + "&type=${type}" +
"&keyc=${keyc}" + "&keyc=${keyc}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/sendEmail", requestBody, "UTF-8") val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/sendEmail", requestBody, "UTF-8")
it.onSuccess(GSON.fromJson(ret, Result::class.java)) it.onSuccess(GSON.fromJson(ret, Result::class.java))
}).compose { RxUtils.toSimpleSingle(it) } }).compose { RxUtils.toSimpleSingle(it) }
@ -134,10 +132,10 @@ object UserService2 {
fun webRestore(user: User): Single<Result> { fun webRestore(user: User): Single<Result> {
return Single.create(SingleOnSubscribe<Result> { return Single.create(SingleOnSubscribe<Result> {
val zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip") val zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip")
val mediaType = MediaType.parse("application/x-www-form-urlencoded") val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull()
val body = "username=${user.userName}" + val body = "username=${user.userName}" +
makeAuth() makeAuth()
val requestBody = RequestBody.create(mediaType, body) val requestBody = body.toRequestBody(mediaType)
val input = OkHttpUtils.getInputStream( val input = OkHttpUtils.getInputStream(
URLCONST.USER_URL + "/do/ret", requestBody URLCONST.USER_URL + "/do/ret", requestBody
) )

@ -3,6 +3,9 @@ package xyz.fycz.myreader.util.webdav
import xyz.fycz.myreader.util.webdav.http.Handler import xyz.fycz.myreader.util.webdav.http.Handler
import xyz.fycz.myreader.util.webdav.http.HttpAuth import xyz.fycz.myreader.util.webdav.http.HttpAuth
import okhttp3.* import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.Jsoup import org.jsoup.Jsoup
import xyz.fycz.myreader.util.utils.OkHttpUtils import xyz.fycz.myreader.util.utils.OkHttpUtils
import java.io.File import java.io.File
@ -77,7 +80,7 @@ constructor(urlStr: String) {
this.exists = false this.exists = false
return false return false
} }
response.body()?.let { response.body?.let {
if (it.string().isNotEmpty()) { if (it.string().isNotEmpty()) {
return true return true
} }
@ -97,7 +100,7 @@ constructor(urlStr: String) {
fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> { fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> {
propFindResponse(propsList)?.let { response -> propFindResponse(propsList)?.let { response ->
if (response.isSuccessful) { if (response.isSuccessful) {
response.body()?.let { body -> response.body?.let { body ->
return parseDir(body.string()) return parseDir(body.string())
} }
} }
@ -121,7 +124,7 @@ constructor(urlStr: String) {
.url(url) .url(url)
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
.method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)) .method("PROPFIND", requestPropsStr.toRequestBody("text/plain".toMediaTypeOrNull()))
HttpAuth.auth?.let { HttpAuth.auth?.let {
request.header( request.header(
@ -200,9 +203,9 @@ constructor(urlStr: String) {
fun upload(localPath: String, contentType: String? = null): Boolean { fun upload(localPath: String, contentType: String? = null): Boolean {
val file = File(localPath) val file = File(localPath)
if (!file.exists()) return false if (!file.exists()) return false
val mediaType = if (contentType == null) null else MediaType.parse(contentType) val mediaType = contentType?.toMediaTypeOrNull()
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
val fileBody = RequestBody.create(mediaType, file) val fileBody = file.asRequestBody(mediaType)
httpUrl?.let { httpUrl?.let {
val request = Request.Builder() val request = Request.Builder()
.url(it) .url(it)
@ -236,7 +239,7 @@ constructor(urlStr: String) {
request.header("Authorization", Credentials.basic(it.user, it.pass)) request.header("Authorization", Credentials.basic(it.user, it.pass))
} }
try { try {
return OkHttpUtils.getOkHttpClient().newCall(request.build()).execute().body()?.byteStream() return OkHttpUtils.getOkHttpClient().newCall(request.build()).execute().body?.byteStream()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {

@ -98,7 +98,7 @@ public class CircleCheckBox extends View {
0, 0); 0, 0);
try { try {
setTickColorHex(a.getString(R.styleable.CircleCheckbox_tickColor)); setTickColorHex(a.getString(R.styleable.CircleCheckbox_tick_Color));
setTextColorHex(a.getString(R.styleable.CircleCheckbox_textColor)); setTextColorHex(a.getString(R.styleable.CircleCheckbox_textColor));
setShowOuterCircle(a.getBoolean(R.styleable.CircleCheckbox_showOuterCircle, true)); setShowOuterCircle(a.getBoolean(R.styleable.CircleCheckbox_showOuterCircle, true));
setInnerCircleColorHex(a.getString(R.styleable.CircleCheckbox_innerCircleColor)); setInnerCircleColorHex(a.getString(R.styleable.CircleCheckbox_innerCircleColor));

@ -245,9 +245,9 @@
<string name="set_timer">定时</string> <string name="set_timer">定时</string>
<string name="read_aloud_pause">朗读暂停</string> <string name="read_aloud_pause">朗读暂停</string>
<string name="read_aloud_timer">正在朗读(还剩%d分钟)</string> <string name="read_aloud_timer">正在朗读(还剩%d分钟)</string>
<string name="read_aloud_timerlong">"正在朗读(还剩%d小时%d分)"</string> <string name="read_aloud_timerlong" formatted="false">"正在朗读(还剩%d小时%d分)"</string>
<string name="read_aloud_timerremaining">%d分钟</string> <string name="read_aloud_timerremaining">%d分钟</string>
<string name="read_aloud_timerremaininglong">"%d小时%d分"</string> <string name="read_aloud_timerremaininglong" formatted="false">"%d小时%d分"</string>
<string name="read_aloud_timerstop">"计时已取消"</string> <string name="read_aloud_timerstop">"计时已取消"</string>
<string name="show_status">显示状态栏</string> <string name="show_status">显示状态栏</string>
<string name="always_next">全屏点击翻下页</string> <string name="always_next">全屏点击翻下页</string>
@ -453,7 +453,7 @@
<string name="debug_toc">测试目录列表</string> <string name="debug_toc">测试目录列表</string>
<string name="debug_content">测试章节内容</string> <string name="debug_content">测试章节内容</string>
<string name="debug">测试</string> <string name="debug">测试</string>
<string name="debug_desc">书源名称:%s\n书源URL:%s\n测试URL:%s</string> <string name="debug_desc" formatted="false">书源名称:%s\n书源URL:%s\n测试URL:%s</string>
<string name="enable_source">启用书源</string> <string name="enable_source">启用书源</string>
<string name="parser">解析器</string> <string name="parser">解析器</string>
<string name="all_source">所有书源</string> <string name="all_source">所有书源</string>
@ -461,7 +461,7 @@
<string name="ad_setting">广告设置</string> <string name="ad_setting">广告设置</string>
<string name="splash_ad">开屏广告</string> <string name="splash_ad">开屏广告</string>
<string name="splash_ad_times">每日广告显示次数</string> <string name="splash_ad_times">每日广告显示次数</string>
<string name="splash_cur_ad_times">当前次数:%s,今日已显示次数:%s</string> <string name="splash_cur_ad_times" formatted="false">当前次数:%s,今日已显示次数:%s</string>
<string name="ad">广告总开关</string> <string name="ad">广告总开关</string>
<string name="book_detail_ad">详情页广告</string> <string name="book_detail_ad">详情页广告</string>
<string name="book_detail_ad_sc">详情页广告开关</string> <string name="book_detail_ad_sc">详情页广告开关</string>

@ -66,7 +66,7 @@
<declare-styleable name="CircleCheckbox"> <declare-styleable name="CircleCheckbox">
<attr name="showOuterCircle" format="boolean" /> <attr name="showOuterCircle" format="boolean" />
<attr name="tickColor" format="string" /> <attr name="tick_Color" format="string" />
<attr name="outerCircleColor" format="string" /> <attr name="outerCircleColor" format="string" />
<attr name="innerCircleColor" format="string" /> <attr name="innerCircleColor" format="string" />
<attr name="textColor" format="string" /> <attr name="textColor" format="string" />

Loading…
Cancel
Save