适配新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.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'

@ -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.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<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}" +
"&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<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}" +
"&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<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}" +
"&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<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}" +
"&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<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}" +
"&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<Result> {
return Single.create(SingleOnSubscribe<Result> {
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
)

@ -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<String> = ArrayList()): List<WebDav> {
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) {

@ -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));

@ -245,9 +245,9 @@
<string name="set_timer">定时</string>
<string name="read_aloud_pause">朗读暂停</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_timerremaininglong">"%d小时%d分"</string>
<string name="read_aloud_timerremaininglong" formatted="false">"%d小时%d分"</string>
<string name="read_aloud_timerstop">"计时已取消"</string>
<string name="show_status">显示状态栏</string>
<string name="always_next">全屏点击翻下页</string>
@ -453,7 +453,7 @@
<string name="debug_toc">测试目录列表</string>
<string name="debug_content">测试章节内容</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="parser">解析器</string>
<string name="all_source">所有书源</string>
@ -461,7 +461,7 @@
<string name="ad_setting">广告设置</string>
<string name="splash_ad">开屏广告</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="book_detail_ad">详情页广告</string>
<string name="book_detail_ad_sc">详情页广告开关</string>

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

Loading…
Cancel
Save