This commit is contained in:
Horis 2023-12-17 23:04:07 +08:00
parent 4ad32a3291
commit d8023474ed
19 changed files with 102 additions and 42 deletions

View File

@ -63,11 +63,11 @@ class ReaderProvider : ContentProvider() {
selectionArgs: Array<String>?
): Int {
if (sMatcher.match(uri) < 0) return -1
when (RequestCode.values()[sMatcher.match(uri)]) {
when (RequestCode.entries[sMatcher.match(uri)]) {
RequestCode.DeleteBookSources -> BookSourceController.deleteSources(selection)
RequestCode.DeleteRssSources -> BookSourceController.deleteSources(selection)
else -> throw IllegalStateException(
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name
"Unexpected value: " + RequestCode.entries[sMatcher.match(uri)].name
)
}
return 0
@ -78,7 +78,7 @@ class ReaderProvider : ContentProvider() {
override fun insert(uri: Uri, values: ContentValues?): Uri? {
if (sMatcher.match(uri) < 0) return null
runBlocking {
when (RequestCode.values()[sMatcher.match(uri)]) {
when (RequestCode.entries[sMatcher.match(uri)]) {
RequestCode.SaveBookSource -> values?.let {
BookSourceController.saveSource(values.getAsString(postBodyKey))
}
@ -104,7 +104,7 @@ class ReaderProvider : ContentProvider() {
}
else -> throw IllegalStateException(
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name
"Unexpected value: " + RequestCode.entries[sMatcher.match(uri)].name
)
}
}
@ -125,7 +125,7 @@ class ReaderProvider : ContentProvider() {
uri.getQueryParameter("path")?.let {
map["path"] = arrayListOf(it)
}
return if (sMatcher.match(uri) < 0) null else when (RequestCode.values()[sMatcher.match(uri)]) {
return if (sMatcher.match(uri) < 0) null else when (RequestCode.entries[sMatcher.match(uri)]) {
RequestCode.GetBookSource -> SimpleCursor(BookSourceController.getSource(map))
RequestCode.GetBookSources -> SimpleCursor(BookSourceController.sources)
RequestCode.GetRssSource -> SimpleCursor(RssSourceController.getSource(map))
@ -136,7 +136,7 @@ class ReaderProvider : ContentProvider() {
RequestCode.GetChapterList -> SimpleCursor(BookController.getChapterList(map))
RequestCode.GetBookCover -> SimpleCursor(BookController.getCover(map))
else -> throw IllegalStateException(
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name
"Unexpected value: " + RequestCode.entries[sMatcher.match(uri)].name
)
}
}

View File

@ -1,13 +1,18 @@
package io.legado.app.data.dao
import androidx.lifecycle.LiveData
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import io.legado.app.constant.BookType
import io.legado.app.data.entities.BookGroup
import kotlinx.coroutines.flow.Flow
@Dao
abstract interface BookGroupDao {
interface BookGroupDao {
@Query("select * from book_groups where groupId = :id")
fun getByID(id: Long): BookGroup?

View File

@ -1,6 +1,11 @@
package io.legado.app.data.dao
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import io.legado.app.constant.AppPattern
import io.legado.app.data.entities.ReplaceRule
import io.legado.app.utils.cnCompare
@ -97,7 +102,7 @@ interface ReplaceRuleDao {
}
}
fun allGroups(): List<String> =dealGroups(allGroupsUnProcessed)
fun allGroups(): List<String> = dealGroups(allGroupsUnProcessed)
fun flowGroups(): Flow<List<String>> {
return flowGroupsUnProcessed().map { list ->

View File

@ -199,6 +199,7 @@ object AppWebDav {
.toSet()
}
@Suppress("unused")
suspend fun exportWebDav(byteArray: ByteArray, fileName: String) {
if (!NetworkUtils.isAvailable()) return
try {

View File

@ -3,7 +3,6 @@ package io.legado.app.help
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import io.legado.app.R
import io.legado.app.utils.toastOnUi
import splitties.init.appCtx

View File

@ -12,6 +12,7 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.Connection
@Suppress("ConstPropertyName")
object CookieManager {
/**
* <domain>_session_cookie 会话期 cookie应用重启后失效

View File

@ -27,11 +27,11 @@ class CronetInterceptor(private val cookieJar: CookieJar) : Interceptor {
builder.removeHeader("Accept-Encoding")
val newReq = builder.build()
proceedWithCronet(newReq, chain.call())?.let { response ->
proceedWithCronet(newReq, chain.call())/*?.let { response ->
//从Response 中保存Cookie到CookieJar
//cookieJar.receiveHeaders(newReq.url, response.headers)
response
} ?: chain.proceed(original)
}*/ ?: chain.proceed(original)
} catch (e: Exception) {
//不能抛出错误,抛出错误会导致应用崩溃
//遇到Cronet处理有问题时的情况如证书过期等等回退到okhttp处理

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
@file:Suppress("NOTHING_TO_INLINE", "unused")
@file:Suppress("unused")
package io.legado.app.lib.dialogs

View File

@ -16,6 +16,10 @@ import org.seimicrawler.xpath.JXNode
@Keep
class AnalyzeByJSoup(doc: Any) {
companion object {
private val nullSet = setOf(null)
}
private var element: Element = parse(doc)
private fun parse(doc: Any): Element {
@ -220,6 +224,7 @@ class AnalyzeByJSoup(doc: Any) {
textS.add(text)
}
}
"textNodes" -> for (element in elements) {
val tn = arrayListOf<String>()
val contentEs = element.textNodes()
@ -233,12 +238,14 @@ class AnalyzeByJSoup(doc: Any) {
textS.add(tn.joinToString("\n"))
}
}
"ownText" -> for (element in elements) {
val text = element.ownText()
if (text.isNotEmpty()) {
textS.add(text)
}
}
"html" -> {
elements.select("script").remove()
elements.select("style").remove()
@ -247,6 +254,7 @@ class AnalyzeByJSoup(doc: Any) {
textS.add(html)
}
}
"all" -> textS.add(elements.outerHtml())
else -> for (element in elements) {
@ -359,7 +367,7 @@ class AnalyzeByJSoup(doc: Any) {
for (pcInt in indexSet) elements[pcInt] = null
elements.removeAll(listOf(null)) //测试过,这样就行
elements.removeAll(nullSet) //测试过,这样就行
} else if (split == '.') { //选择

View File

@ -1,7 +1,6 @@
package io.legado.app.ui.association
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.os.postDelayed

View File

@ -8,7 +8,6 @@ import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppLog
import io.legado.app.constant.AppPattern
import io.legado.app.constant.EventBus
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
@ -22,15 +21,19 @@ import io.legado.app.help.config.SourceConfig
import io.legado.app.help.coroutine.CompositeCoroutine
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.model.webBook.WebBook
import io.legado.app.utils.postEvent
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.*
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ExecutorCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import java.util.*
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
import kotlin.math.min
@ -319,22 +322,26 @@ open class ChangeBookSourceViewModel(application: Application) : BaseViewModel(a
}
fun onLoadWordCountChecked(isChecked: Boolean) {
postEvent(EventBus.SOURCE_CHANGED, "")
if (isChecked) {
startRefreshList(searchBooks.filter { it.chapterWordCountText == null })
startRefreshList(true)
}
}
/**
* 刷新列表
*/
fun startRefreshList(refreshList: List<SearchBook> = searchBooks) {
fun startRefreshList(onlyRefreshNoWordCountBook: Boolean = false) {
execute {
if (refreshList.isEmpty()) return@execute
stopSearch()
searchBookList.clear()
searchBookList.addAll(refreshList)
searchBooks.removeAll(refreshList)
if (onlyRefreshNoWordCountBook) {
val noWordCountBook = searchBooks.filter { it.chapterWordCountText == null }
searchBookList.addAll(noWordCountBook)
searchBooks.removeIf { it.chapterWordCountText == null }
} else {
searchBookList.addAll(searchBooks)
searchBooks.clear()
}
searchCallback?.upAdapter()
searchStateData.postValue(true)
initSearchPool()

View File

@ -251,19 +251,23 @@ class ChangeChapterSourceDialog() : BaseDialogFragment(R.layout.dialog_chapter_c
item.isChecked = !item.isChecked
viewModel.refresh()
}
R.id.menu_load_info -> {
AppConfig.changeSourceLoadInfo = !item.isChecked
item.isChecked = !item.isChecked
}
R.id.menu_load_toc -> {
AppConfig.changeSourceLoadToc = !item.isChecked
item.isChecked = !item.isChecked
}
R.id.menu_load_word_count -> {
AppConfig.changeSourceLoadWordCount = !item.isChecked
item.isChecked = !item.isChecked
viewModel.onLoadWordCountChecked(item.isChecked)
}
R.id.menu_start_stop -> viewModel.startOrStopSearch()
R.id.menu_source_manage -> startActivity<BookSourceActivity>()
else -> if (item?.groupId == R.id.source_group && !item.isChecked) {

View File

@ -7,7 +7,11 @@ import android.content.Intent
import android.content.pm.ResolveInfo
import android.net.Uri
import android.os.Build
import android.view.*
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.annotation.RequiresApi
import androidx.appcompat.view.SupportMenuInflater
@ -21,7 +25,14 @@ import io.legado.app.constant.PreferKey
import io.legado.app.databinding.ItemTextBinding
import io.legado.app.databinding.PopupActionMenuBinding
import io.legado.app.help.config.AppConfig
import io.legado.app.utils.*
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.gone
import io.legado.app.utils.isAbsUrl
import io.legado.app.utils.printOnDebug
import io.legado.app.utils.sendToClip
import io.legado.app.utils.share
import io.legado.app.utils.toastOnUi
import io.legado.app.utils.visible
@SuppressLint("RestrictedApi")
class TextActionMenu(private val context: Context, private val callBack: CallBack) :
@ -108,9 +119,11 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
windowHeight - startTopY
)
}
endBottomY - startBottomY > 500 -> {
showAtLocation(view, Gravity.TOP or Gravity.START, startX, startBottomY)
}
else -> {
showAtLocation(view, Gravity.TOP or Gravity.START, endX, endBottomY)
}
@ -130,6 +143,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
startTopY - popupHeight
)
}
endBottomY - startBottomY > 500 -> {
showAtLocation(
view,
@ -138,6 +152,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
startBottomY
)
}
else -> {
showAtLocation(
view,
@ -215,6 +230,7 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
context.toastOnUi(it.localizedMessage ?: "ERROR")
}
}
else -> item.intent?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
it.putExtra(Intent.EXTRA_PROCESS_TEXT, callBack.selectedText)
@ -233,7 +249,6 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac
@RequiresApi(Build.VERSION_CODES.M)
private fun getSupportedActivities(): List<ResolveInfo> {
@Suppress("DEPRECATION")
return context.packageManager
.queryIntentActivities(createProcessTextIntent(), 0)
}

View File

@ -23,7 +23,12 @@ import io.legado.app.lib.theme.getPrimaryTextColor
import io.legado.app.model.ReadBook
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.font.FontSelectDialog
import io.legado.app.utils.*
import io.legado.app.utils.ChineseUtils
import io.legado.app.utils.ColorUtils
import io.legado.app.utils.dpToPx
import io.legado.app.utils.getIndexById
import io.legado.app.utils.postEvent
import io.legado.app.utils.showDialogFragment
import io.legado.app.utils.viewbindingdelegate.viewBinding
import splitties.views.onLongClick
@ -102,7 +107,7 @@ class ReadStyleDialog : BaseDialogFragment(R.layout.dialog_read_book_style),
private fun initViewEvent() = binding.run {
chineseConverter.onChanged {
ChineseUtils.unLoad(*TransType.values())
ChineseUtils.unLoad(*TransType.entries.toTypedArray())
postEvent(EventBus.UP_CONFIG, true)
}
textFontWeightConverter.onChanged {

View File

@ -11,10 +11,7 @@ class ExploreDiffItemCallBack : DiffUtil.ItemCallback<BookSource>() {
}
override fun areContentsTheSame(oldItem: BookSource, newItem: BookSource): Boolean {
if (oldItem.bookSourceName != newItem.bookSourceName) {
return false
}
return true
return oldItem.bookSourceName == newItem.bookSourceName
}
}

View File

@ -212,13 +212,16 @@ class VerticalSeekBar @JvmOverloads constructor(context: Context, attrs: Attribu
direction = if (mRotationAngle == ROTATION_ANGLE_CW_90) 1 else -1
handled = true
}
KeyEvent.KEYCODE_DPAD_UP -> {
direction = if (mRotationAngle == ROTATION_ANGLE_CW_270) 1 else -1
handled = true
}
KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT ->
// move view focus to previous/next view
return false
else -> handled = false
}
@ -258,7 +261,7 @@ class VerticalSeekBar @JvmOverloads constructor(context: Context, attrs: Attribu
)
m.isAccessible = true
mMethodSetProgressFromUser = m
} catch (e: NoSuchMethodException) {
} catch (_: NoSuchMethodException) {
}
}
@ -266,9 +269,9 @@ class VerticalSeekBar @JvmOverloads constructor(context: Context, attrs: Attribu
if (mMethodSetProgressFromUser != null) {
try {
mMethodSetProgressFromUser!!.invoke(this, progress, fromUser)
} catch (e: IllegalArgumentException) {
} catch (e: IllegalAccessException) {
} catch (e: InvocationTargetException) {
} catch (_: IllegalArgumentException) {
} catch (_: IllegalAccessException) {
} catch (_: InvocationTargetException) {
}
} else {
@ -310,6 +313,7 @@ class VerticalSeekBar @JvmOverloads constructor(context: Context, attrs: Attribu
canvas.rotate(90f)
canvas.translate(0f, (-super.getWidth()).toFloat())
}
ROTATION_ANGLE_CW_270 -> {
canvas.rotate(-90f)
canvas.translate((-super.getHeight()).toFloat(), 0f)

View File

@ -5,9 +5,18 @@ package io.legado.app.utils
import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent
import android.app.PendingIntent.*
import android.app.PendingIntent.FLAG_MUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.PendingIntent.getActivity
import android.app.PendingIntent.getBroadcast
import android.app.PendingIntent.getService
import android.app.Service
import android.content.*
import android.content.BroadcastReceiver
import android.content.ClipData
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.content.res.Configuration
@ -355,7 +364,6 @@ val Context.isPad: Boolean
val Context.isTv: Boolean
get() = uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
@Suppress("DEPRECATION")
val Context.channel: String
get() {
try {

View File

@ -35,6 +35,7 @@ fun Menu.applyTint(context: Context, theme: Theme = Theme.Auto): Menu = this.let
return menu
}
@SuppressLint("RestrictedApi")
fun Menu.applyOpenTint(context: Context) {
//展开菜单显示图标
if (this.javaClass.simpleName.equals("MenuBuilder", ignoreCase = true)) {

View File

@ -9,6 +9,7 @@ import java.io.IOException
import java.nio.ByteBuffer
import java.nio.channels.SeekableByteChannel
@Suppress("unused")
@SuppressLint("NewApi")
class ParcelFileDescriptorChannel(private val pfd: ParcelFileDescriptor) : SeekableByteChannel {
@Throws(IOException::class)