@@ -359,6 +359,13 @@
|
|||||||
<data android:scheme="yuedu" />
|
<data android:scheme="yuedu" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<!-- 验证码输入 -->
|
||||||
|
<activity
|
||||||
|
android:name=".ui.association.VerificationCodeActivity"
|
||||||
|
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
|
||||||
|
android:exported="true"
|
||||||
|
android:theme="@style/AppTheme.Transparent">
|
||||||
|
</activity>
|
||||||
<!-- 打开文件 -->
|
<!-- 打开文件 -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.association.FileAssociationActivity"
|
android:name=".ui.association.FileAssociationActivity"
|
||||||
|
|||||||
@@ -67,12 +67,19 @@ java.webView(html: String?, url: String?, js: String?): String
|
|||||||
* @param url 要打开的链接
|
* @param url 要打开的链接
|
||||||
* @param title 浏览器的标题
|
* @param title 浏览器的标题
|
||||||
java.startBrowser(url: String, title: String)
|
java.startBrowser(url: String, title: String)
|
||||||
|
|
||||||
|
* 使用内置浏览器打开链接,并等待网页结果 .body()获取网页内容
|
||||||
|
java.startBrowserAwait(url: String, title: String): StrResponse
|
||||||
```
|
```
|
||||||
* 调试
|
* 调试
|
||||||
```
|
```
|
||||||
java.log(msg)
|
java.log(msg)
|
||||||
java.logType(var)
|
java.logType(var)
|
||||||
```
|
```
|
||||||
|
* 获取用户输入的验证码
|
||||||
|
```
|
||||||
|
java.getVerificationCode(imageUrl)
|
||||||
|
```
|
||||||
* 弹窗提示
|
* 弹窗提示
|
||||||
```
|
```
|
||||||
java.longToast(msg: Any?)
|
java.longToast(msg: Any?)
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
||||||
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
||||||
|
|
||||||
|
**2022/05/04**
|
||||||
|
|
||||||
|
* js添加 getVerificationCode startBrowserAwait
|
||||||
|
|
||||||
**2022/05/02**
|
**2022/05/02**
|
||||||
|
|
||||||
* 优化强调色和文字颜色一样的情况下一些文字的显示
|
* 优化强调色和文字颜色一样的情况下一些文字的显示
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.legado.app.help
|
package io.legado.app.help
|
||||||
|
|
||||||
|
import androidx.collection.LruCache
|
||||||
import io.legado.app.data.appDb
|
import io.legado.app.data.appDb
|
||||||
import io.legado.app.data.entities.Cache
|
import io.legado.app.data.entities.Cache
|
||||||
import io.legado.app.model.analyzeRule.QueryTTF
|
import io.legado.app.model.analyzeRule.QueryTTF
|
||||||
@@ -10,6 +11,11 @@ import splitties.init.appCtx
|
|||||||
object CacheManager {
|
object CacheManager {
|
||||||
|
|
||||||
private val queryTTFMap = hashMapOf<String, Pair<Long, QueryTTF>>()
|
private val queryTTFMap = hashMapOf<String, Pair<Long, QueryTTF>>()
|
||||||
|
private val memoryLruCache = object : LruCache<String, Cache>(100) {
|
||||||
|
override fun sizeOf(key: String, value: Cache): Int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* saveTime 单位为秒
|
* saveTime 单位为秒
|
||||||
@@ -23,13 +29,26 @@ object CacheManager {
|
|||||||
is ByteArray -> ACache.get(appCtx).put(key, value, saveTime)
|
is ByteArray -> ACache.get(appCtx).put(key, value, saveTime)
|
||||||
else -> {
|
else -> {
|
||||||
val cache = Cache(key, value.toString(), deadline)
|
val cache = Cache(key, value.toString(), deadline)
|
||||||
|
memoryLruCache.put(key, cache)
|
||||||
appDb.cacheDao.insert(cache)
|
appDb.cacheDao.insert(cache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(key: String): String? {
|
fun get(key: String): String? {
|
||||||
return appDb.cacheDao.get(key, System.currentTimeMillis())
|
return getFromMemory(key) ?: appDb.cacheDao.get(key, System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
|
||||||
|
//从内存中获取数据 使用lrucache 支持过期功能
|
||||||
|
private fun getFromMemory(key: String): String? {
|
||||||
|
val cache = memoryLruCache.get(key) ?: return null
|
||||||
|
val deadline = cache!!.deadline
|
||||||
|
return if (deadline == 0L || deadline > System.currentTimeMillis()) {
|
||||||
|
cache!!.value
|
||||||
|
} else {
|
||||||
|
memoryLruCache.remove(key)
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInt(key: String): Int? {
|
fun getInt(key: String): Int? {
|
||||||
@@ -70,6 +89,7 @@ object CacheManager {
|
|||||||
|
|
||||||
fun delete(key: String) {
|
fun delete(key: String) {
|
||||||
appDb.cacheDao.delete(key)
|
appDb.cacheDao.delete(key)
|
||||||
|
memoryLruCache.remove(key)
|
||||||
ACache.get(appCtx).remove(key)
|
ACache.get(appCtx).remove(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,6 @@ import io.legado.app.help.http.*
|
|||||||
import io.legado.app.model.Debug
|
import io.legado.app.model.Debug
|
||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
import io.legado.app.model.analyzeRule.QueryTTF
|
import io.legado.app.model.analyzeRule.QueryTTF
|
||||||
import io.legado.app.ui.browser.WebViewActivity
|
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
@@ -133,18 +132,28 @@ interface JsExtensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用内置浏览器打开链接,可用于获取验证码 手动验证网站防爬
|
* 使用内置浏览器打开链接,手动验证网站防爬
|
||||||
* @param url 要打开的链接
|
* @param url 要打开的链接
|
||||||
* @param title 浏览器页面的标题
|
* @param title 浏览器页面的标题
|
||||||
*/
|
*/
|
||||||
fun startBrowser(url: String, title: String) {
|
fun startBrowser(url: String, title: String) {
|
||||||
appCtx.startActivity<WebViewActivity> {
|
SourceVerificationHelp.startBrowser(getSource(), url, title)
|
||||||
putExtra("title", title)
|
|
||||||
putExtra("url", url)
|
|
||||||
IntentData.put(url, getSource()?.getHeaderMap(true))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用内置浏览器打开链接,并等待网页结果
|
||||||
|
*/
|
||||||
|
fun startBrowserAwait(url: String, title: String): StrResponse {
|
||||||
|
return StrResponse(url, SourceVerificationHelp.getVerificationResult(getSource(), url, title, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开图片验证码对话框,等待返回验证结果
|
||||||
|
*/
|
||||||
|
fun getVerificationCode(imageUrl: String): String {
|
||||||
|
return SourceVerificationHelp.getVerificationResult(getSource(), imageUrl, "", false)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 可从网络,本地文件(阅读私有缓存目录和书籍保存位置支持相对路径)导入JavaScript脚本
|
* 可从网络,本地文件(阅读私有缓存目录和书籍保存位置支持相对路径)导入JavaScript脚本
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package io.legado.app.help
|
||||||
|
|
||||||
|
import io.legado.app.utils.startActivity
|
||||||
|
import io.legado.app.constant.AppLog
|
||||||
|
import io.legado.app.exception.NoStackTraceException
|
||||||
|
import io.legado.app.data.entities.BaseSource
|
||||||
|
import io.legado.app.ui.browser.WebViewActivity
|
||||||
|
import io.legado.app.ui.association.VerificationCodeActivity
|
||||||
|
import splitties.init.appCtx
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
|
||||||
|
object SourceVerificationHelp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取书源验证结果
|
||||||
|
* 图片验证码 防爬 滑动验证码 点击字符 等等
|
||||||
|
*/
|
||||||
|
fun getVerificationResult(source: BaseSource?, url: String, title: String, useBrowser: Boolean): String {
|
||||||
|
source ?: throw NoStackTraceException("getVerificationResult parameter source cannot be null")
|
||||||
|
return runBlocking {
|
||||||
|
val key = "${source?.getKey() ?: ""}_verificationResult"
|
||||||
|
CacheManager.delete(key)
|
||||||
|
|
||||||
|
if (!useBrowser) {
|
||||||
|
appCtx.startActivity<VerificationCodeActivity> {
|
||||||
|
putExtra("imageUrl", url)
|
||||||
|
putExtra("sourceOrigin", source?.getKey())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startBrowser(source, url, title, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var waitUserInput: Boolean = false
|
||||||
|
while(CacheManager.get(key) == null) {
|
||||||
|
if (!waitUserInput) {
|
||||||
|
AppLog.putDebug("等待返回验证结果...")
|
||||||
|
waitUserInput = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CacheManager.get(key)!!.let {
|
||||||
|
if (it.isBlank()) {
|
||||||
|
throw NoStackTraceException("验证结果为空")
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动内置浏览器
|
||||||
|
@param saveResult 保存网页源代码到数据库
|
||||||
|
*/
|
||||||
|
fun startBrowser(source: BaseSource?, url: String, title: String, saveResult: Boolean? = false) {
|
||||||
|
source ?: throw NoStackTraceException("startBrowser parameter source cannot be null")
|
||||||
|
appCtx.startActivity<WebViewActivity> {
|
||||||
|
putExtra("title", title)
|
||||||
|
putExtra("url", url)
|
||||||
|
putExtra("sourceOrigin", source?.getKey())
|
||||||
|
putExtra("sourceVerificationEnable", saveResult)
|
||||||
|
IntentData.put(url, source?.getHeaderMap(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkActivityStatus(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package io.legado.app.ui.association
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import io.legado.app.base.BaseActivity
|
||||||
|
import io.legado.app.databinding.ActivityTranslucenceBinding
|
||||||
|
import io.legado.app.utils.showDialogFragment
|
||||||
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码
|
||||||
|
*/
|
||||||
|
class VerificationCodeActivity :
|
||||||
|
BaseActivity<ActivityTranslucenceBinding>() {
|
||||||
|
|
||||||
|
override val binding by viewBinding(ActivityTranslucenceBinding::inflate)
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
intent.getStringExtra("imageUrl")?.let {
|
||||||
|
val sourceOrigin = intent.getStringExtra("sourceOrigin")
|
||||||
|
showDialogFragment(
|
||||||
|
VerificationCodeDialog(it, sourceOrigin)
|
||||||
|
)
|
||||||
|
} ?: finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package io.legado.app.ui.association
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.net.Uri
|
||||||
|
import com.bumptech.glide.request.RequestOptions
|
||||||
|
import io.legado.app.R
|
||||||
|
import io.legado.app.base.BaseDialogFragment
|
||||||
|
import io.legado.app.databinding.DialogVerificationCodeViewBinding
|
||||||
|
import io.legado.app.help.CacheManager
|
||||||
|
import io.legado.app.help.glide.ImageLoader
|
||||||
|
import io.legado.app.help.glide.OkHttpModelLoader
|
||||||
|
import io.legado.app.lib.theme.primaryColor
|
||||||
|
import io.legado.app.ui.widget.dialog.PhotoDialog
|
||||||
|
import io.legado.app.utils.setLayout
|
||||||
|
import io.legado.app.utils.showDialogFragment
|
||||||
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片验证码对话框
|
||||||
|
* 结果保存在数据库中
|
||||||
|
* val key = "${sourceOrigin ?: ""}_verificationResult"
|
||||||
|
* CacheManager.get(key)
|
||||||
|
*/
|
||||||
|
class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification_code_view) {
|
||||||
|
|
||||||
|
constructor(imageUrl: String, sourceOrigin: String? = null) : this() {
|
||||||
|
arguments = Bundle().apply {
|
||||||
|
putString("sourceOrigin", sourceOrigin)
|
||||||
|
putString("imageUrl", imageUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val binding by viewBinding(DialogVerificationCodeViewBinding::bind)
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
setLayout(1f, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
binding.run {
|
||||||
|
toolBar.setBackgroundColor(primaryColor)
|
||||||
|
val sourceOrigin = arguments?.getString("sourceOrigin")
|
||||||
|
val key = "${sourceOrigin ?: ""}_verificationResult"
|
||||||
|
arguments?.getString("imageUrl")?.let { imageUrl ->
|
||||||
|
ImageLoader.load(requireContext(), imageUrl).apply {
|
||||||
|
sourceOrigin?.let {
|
||||||
|
apply(
|
||||||
|
RequestOptions().set(
|
||||||
|
OkHttpModelLoader.sourceOriginOption,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.error(R.drawable.image_loading_error)
|
||||||
|
.into(ivImage)
|
||||||
|
ivImage.setOnClickListener {
|
||||||
|
showDialogFragment(PhotoDialog(imageUrl, sourceOrigin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tvOk.setOnClickListener {
|
||||||
|
val verificationCode = binding.verificationCode.text.toString()
|
||||||
|
verificationCode?.let {
|
||||||
|
CacheManager.put(key, it)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tvCancel.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
val sourceOrigin = arguments?.getString("sourceOrigin")
|
||||||
|
val key = "${sourceOrigin ?: ""}_verificationResult"
|
||||||
|
CacheManager.get(key) ?: CacheManager.put(key, "")
|
||||||
|
super.onDestroy()
|
||||||
|
activity?.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import io.legado.app.ui.document.HandleFileContract
|
|||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.*
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
|
class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
|
||||||
|
|
||||||
@@ -65,6 +66,12 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
|
|||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.menu_open_in_browser -> openUrl(viewModel.baseUrl)
|
R.id.menu_open_in_browser -> openUrl(viewModel.baseUrl)
|
||||||
R.id.menu_copy_url -> sendToClip(viewModel.baseUrl)
|
R.id.menu_copy_url -> sendToClip(viewModel.baseUrl)
|
||||||
|
R.id.menu_ok -> {
|
||||||
|
if (viewModel.sourceVerificationEnable) {
|
||||||
|
binding.titleBar.snackbar(R.string.ok)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.onCompatOptionsItemSelected(item)
|
return super.onCompatOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
@@ -135,7 +142,6 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
|
|||||||
viewModel.saveImage(webPic, path)
|
viewModel.saveImage(webPic, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectSaveFolder() {
|
private fun selectSaveFolder() {
|
||||||
val default = arrayListOf<SelectItem<Int>>()
|
val default = arrayListOf<SelectItem<Int>>()
|
||||||
val path = ACache.get(this).getAsString(imagePathKey)
|
val path = ACache.get(this).getAsString(imagePathKey)
|
||||||
@@ -176,6 +182,9 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
runBlocking {
|
||||||
|
viewModel.saveVerificationResult()
|
||||||
|
}
|
||||||
binding.webView.destroy()
|
binding.webView.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.documentfile.provider.DocumentFile
|
|||||||
import io.legado.app.base.BaseViewModel
|
import io.legado.app.base.BaseViewModel
|
||||||
import io.legado.app.constant.AppConst
|
import io.legado.app.constant.AppConst
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
|
import io.legado.app.help.CacheManager
|
||||||
import io.legado.app.help.IntentData
|
import io.legado.app.help.IntentData
|
||||||
import io.legado.app.help.http.newCallResponseBody
|
import io.legado.app.help.http.newCallResponseBody
|
||||||
import io.legado.app.help.http.okHttpClient
|
import io.legado.app.help.http.okHttpClient
|
||||||
@@ -21,6 +22,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
var baseUrl: String = ""
|
var baseUrl: String = ""
|
||||||
var html: String? = null
|
var html: String? = null
|
||||||
val headerMap: HashMap<String, String> = hashMapOf()
|
val headerMap: HashMap<String, String> = hashMapOf()
|
||||||
|
var sourceVerificationEnable: Boolean = false
|
||||||
|
var sourceOrigin: String = ""
|
||||||
|
|
||||||
fun initData(
|
fun initData(
|
||||||
intent: Intent,
|
intent: Intent,
|
||||||
@@ -29,6 +32,8 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
execute {
|
execute {
|
||||||
val url = intent.getStringExtra("url")
|
val url = intent.getStringExtra("url")
|
||||||
?: throw NoStackTraceException("url不能为空")
|
?: throw NoStackTraceException("url不能为空")
|
||||||
|
sourceOrigin = intent.getStringExtra("sourceOrigin") ?: ""
|
||||||
|
sourceVerificationEnable = intent.getBooleanExtra("sourceVerificationEnable", false)
|
||||||
val headerMapF = IntentData.get<Map<String, String>>(url)
|
val headerMapF = IntentData.get<Map<String, String>>(url)
|
||||||
val analyzeUrl = AnalyzeUrl(url, headerMapF = headerMapF)
|
val analyzeUrl = AnalyzeUrl(url, headerMapF = headerMapF)
|
||||||
baseUrl = analyzeUrl.url
|
baseUrl = analyzeUrl.url
|
||||||
@@ -78,5 +83,12 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun saveVerificationResult() {
|
||||||
|
if (sourceVerificationEnable) {
|
||||||
|
val key = "${sourceOrigin}_verificationResult"
|
||||||
|
html = AnalyzeUrl(baseUrl, headerMapF = headerMap).getStrResponse(useWebView = false).body
|
||||||
|
CacheManager.put(key, html ?: "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ class WebViewLoginFragment : BaseFragment(R.layout.fragment_web_view_login) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompatCreateOptionsMenu(menu: Menu) {
|
override fun onCompatCreateOptionsMenu(menu: Menu) {
|
||||||
menuInflater.inflate(R.menu.source_login, menu)
|
menuInflater.inflate(R.menu.source_webview_login, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompatOptionsItemSelected(item: MenuItem) {
|
override fun onCompatOptionsItemSelected(item: MenuItem) {
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/tool_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="?attr/actionBarStyle"
|
||||||
|
app:title="@string/input_verification_code"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||||
|
app:titleTextAppearance="@style/ToolbarTitle" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/iv_image"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:paddingTop="3dp"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
|
<io.legado.app.ui.widget.text.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:paddingTop="3dp">
|
||||||
|
|
||||||
|
<io.legado.app.lib.theme.view.ThemeEditText
|
||||||
|
android:id="@+id/verification_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/verification_code"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck" />
|
||||||
|
|
||||||
|
</io.legado.app.ui.widget.text.TextInputLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.flexbox.FlexboxLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
app:justifyContent="flex_end">
|
||||||
|
|
||||||
|
<io.legado.app.ui.widget.text.AccentTextView
|
||||||
|
android:id="@+id/tv_cancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="@string/cancel"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
<io.legado.app.ui.widget.text.AccentTextView
|
||||||
|
android:id="@+id/tv_ok"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="@string/ok"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
</com.google.android.flexbox.FlexboxLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:ignore="AlwaysShowAction">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_ok"
|
||||||
|
android:icon="@drawable/ic_check"
|
||||||
|
android:title="@string/ok"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -2,6 +2,12 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_ok"
|
||||||
|
android:icon="@drawable/ic_check"
|
||||||
|
android:title="@string/ok"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_open_in_browser"
|
android:id="@+id/menu_open_in_browser"
|
||||||
android:title="@string/open_in_browser"
|
android:title="@string/open_in_browser"
|
||||||
|
|||||||
@@ -969,5 +969,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -972,5 +972,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -972,5 +972,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -969,5 +969,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -971,5 +971,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -971,5 +971,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -972,5 +972,7 @@
|
|||||||
<string name="change_source_batch">批量换源</string>
|
<string name="change_source_batch">批量换源</string>
|
||||||
<string name="book_type_different">书籍类型不一样</string>
|
<string name="book_type_different">书籍类型不一样</string>
|
||||||
<string name="soure_change_source">是否确认换源</string>
|
<string name="soure_change_source">是否确认换源</string>
|
||||||
|
<string name="input_verification_code">输入验证码</string>
|
||||||
|
<string name="verification_code">验证码</string>
|
||||||
<!-- string end -->
|
<!-- string end -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user