diff --git a/app/build.gradle b/app/build.gradle index c0103d7..6af0ce8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -152,7 +152,7 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.3' 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 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' diff --git a/app/src/main/java/xyz/fycz/myreader/model/JSExtensions.kt b/app/src/main/java/xyz/fycz/myreader/model/JSExtensions.kt deleted file mode 100644 index 60e8c4e..0000000 --- a/app/src/main/java/xyz/fycz/myreader/model/JSExtensions.kt +++ /dev/null @@ -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?): 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? - ): 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) } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt b/app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt index 36b358e..1637365 100644 --- a/app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt +++ b/app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt @@ -5,8 +5,10 @@ import io.reactivex.SingleOnSubscribe import io.reactivex.SingleSource import io.reactivex.functions.Function import net.lingala.zip4j.ZipFile -import okhttp3.MediaType -import okhttp3.RequestBody +import net.lingala.zip4j.model.ZipParameters +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.common.APPCONST 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.RxUtils 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 @@ -32,11 +30,11 @@ object UserService2 { fun login(user: User): Single { return Single.create(SingleOnSubscribe { - val mediaType = MediaType.parse("application/x-www-form-urlencoded") + val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val body = "username=${user.userName}" + "&password=${user.password}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/login", requestBody, "UTF-8") it.onSuccess(GSON.fromJson(ret, Result::class.java)) }).compose { RxUtils.toSimpleSingle(it) } @@ -44,7 +42,7 @@ object UserService2 { fun register(user: User, code: String, keyc: String): Single { return Single.create(SingleOnSubscribe { - val mediaType = MediaType.parse("application/x-www-form-urlencoded") + val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val body = "username=${user.userName}" + "&password=${user.password}" + "&email=${user.email}" + @@ -52,7 +50,7 @@ object UserService2 { "&keyc=${keyc}" + "&key=${CyptoUtils.encode(APPCONST.KEY, APPCONST.publicKey)}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/reg", requestBody, "UTF-8") it.onSuccess(GSON.fromJson(ret, Result::class.java)) }).compose { RxUtils.toSimpleSingle(it) } @@ -60,13 +58,13 @@ object UserService2 { fun bindEmail(user: User, code: String, keyc: String): Single { return Single.create(SingleOnSubscribe { - val mediaType = MediaType.parse("application/x-www-form-urlencoded") + val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val body = "username=${user.userName}" + "&email=${user.email}" + "&code=${code}" + "&keyc=${keyc}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/bindEmail", requestBody, "UTF-8") it.onSuccess(GSON.fromJson(ret, Result::class.java)) }).compose { RxUtils.toSimpleSingle(it) } @@ -74,13 +72,13 @@ object UserService2 { fun resetPwd(user: User, code: String, keyc: String): Single { return Single.create(SingleOnSubscribe { - val mediaType = MediaType.parse("application/x-www-form-urlencoded") + val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val body = "email=${user.email}" + "&password=${user.password}" + "&code=${code}" + "&keyc=${keyc}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/resetPwd", requestBody, "UTF-8") it.onSuccess(GSON.fromJson(ret, Result::class.java)) }).compose { RxUtils.toSimpleSingle(it) } @@ -88,12 +86,12 @@ object UserService2 { fun sendEmail(email: String, type: String, keyc: String = ""): Single { return Single.create(SingleOnSubscribe { - val mediaType = MediaType.parse("application/x-www-form-urlencoded") + val mediaType = "application/x-www-form-urlencoded".toMediaTypeOrNull() val body = "email=${email}" + "&type=${type}" + "&keyc=${keyc}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/sendEmail", requestBody, "UTF-8") it.onSuccess(GSON.fromJson(ret, Result::class.java)) }).compose { RxUtils.toSimpleSingle(it) } @@ -134,10 +132,10 @@ object UserService2 { fun webRestore(user: User): Single { return Single.create(SingleOnSubscribe { 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}" + makeAuth() - val requestBody = RequestBody.create(mediaType, body) + val requestBody = body.toRequestBody(mediaType) val input = OkHttpUtils.getInputStream( URLCONST.USER_URL + "/do/ret", requestBody ) diff --git a/app/src/main/java/xyz/fycz/myreader/util/webdav/WebDav.kt b/app/src/main/java/xyz/fycz/myreader/util/webdav/WebDav.kt index a469342..226280c 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/webdav/WebDav.kt +++ b/app/src/main/java/xyz/fycz/myreader/util/webdav/WebDav.kt @@ -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.HttpAuth import okhttp3.* +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody import org.jsoup.Jsoup import xyz.fycz.myreader.util.utils.OkHttpUtils import java.io.File @@ -77,7 +80,7 @@ constructor(urlStr: String) { this.exists = false return false } - response.body()?.let { + response.body?.let { if (it.string().isNotEmpty()) { return true } @@ -97,7 +100,7 @@ constructor(urlStr: String) { fun listFiles(propsList: ArrayList = ArrayList()): List { propFindResponse(propsList)?.let { response -> if (response.isSuccessful) { - response.body()?.let { body -> + response.body?.let { body -> return parseDir(body.string()) } } @@ -121,7 +124,7 @@ constructor(urlStr: String) { .url(url) // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 - .method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)) + .method("PROPFIND", requestPropsStr.toRequestBody("text/plain".toMediaTypeOrNull())) HttpAuth.auth?.let { request.header( @@ -200,9 +203,9 @@ constructor(urlStr: String) { fun upload(localPath: String, contentType: String? = null): Boolean { val file = File(localPath) if (!file.exists()) return false - val mediaType = if (contentType == null) null else MediaType.parse(contentType) + val mediaType = contentType?.toMediaTypeOrNull() // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 - val fileBody = RequestBody.create(mediaType, file) + val fileBody = file.asRequestBody(mediaType) httpUrl?.let { val request = Request.Builder() .url(it) @@ -236,7 +239,7 @@ constructor(urlStr: String) { request.header("Authorization", Credentials.basic(it.user, it.pass)) } try { - return OkHttpUtils.getOkHttpClient().newCall(request.build()).execute().body()?.byteStream() + return OkHttpUtils.getOkHttpClient().newCall(request.build()).execute().body?.byteStream() } catch (e: IOException) { e.printStackTrace() } catch (e: IllegalArgumentException) { diff --git a/app/src/main/java/xyz/fycz/myreader/widget/CircleCheckBox.java b/app/src/main/java/xyz/fycz/myreader/widget/CircleCheckBox.java index ff8dabd..7590306 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/CircleCheckBox.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/CircleCheckBox.java @@ -98,7 +98,7 @@ public class CircleCheckBox extends View { 0, 0); try { - setTickColorHex(a.getString(R.styleable.CircleCheckbox_tickColor)); + setTickColorHex(a.getString(R.styleable.CircleCheckbox_tick_Color)); setTextColorHex(a.getString(R.styleable.CircleCheckbox_textColor)); setShowOuterCircle(a.getBoolean(R.styleable.CircleCheckbox_showOuterCircle, true)); setInnerCircleColorHex(a.getString(R.styleable.CircleCheckbox_innerCircleColor)); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b5a40f3..d4b07bc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -245,9 +245,9 @@ 定时 朗读暂停 正在朗读(还剩%d分钟) - "正在朗读(还剩%d小时%d分)" + "正在朗读(还剩%d小时%d分)" %d分钟 - "%d小时%d分" + "%d小时%d分" "计时已取消" 显示状态栏 全屏点击翻下页 @@ -453,7 +453,7 @@ 测试目录列表 测试章节内容 测试 - 书源名称:%s\n书源URL:%s\n测试URL:%s + 书源名称:%s\n书源URL:%s\n测试URL:%s 启用书源 解析器 所有书源 @@ -461,7 +461,7 @@ 广告设置 开屏广告 每日广告显示次数 - 当前次数:%s,今日已显示次数:%s + 当前次数:%s,今日已显示次数:%s 广告总开关 详情页广告 详情页广告开关 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ae8d236..d1db0a2 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -66,7 +66,7 @@ - +