Merge remote-tracking branch 'origin/master' into master

pull/1126/head
bushixuanqi 3 years ago
commit c215685672
  1. 3
      app/src/main/java/io/legado/app/api/controller/BookController.kt
  2. 5
      app/src/main/java/io/legado/app/base/adapter/ItemAnimation.kt
  3. 3
      app/src/main/java/io/legado/app/base/adapter/animations/AlphaInAnimation.kt
  4. 3
      app/src/main/java/io/legado/app/base/adapter/animations/ScaleInAnimation.kt
  5. 1
      app/src/main/java/io/legado/app/data/entities/Book.kt
  6. 2
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  7. 6
      app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt
  8. 2
      app/src/main/java/io/legado/app/data/entities/SearchBook.kt
  9. 2
      app/src/main/java/io/legado/app/help/AppConfig.kt
  10. 7
      app/src/main/java/io/legado/app/help/BlurTransformation.kt
  11. 6
      app/src/main/java/io/legado/app/help/BookHelp.kt
  12. 2
      app/src/main/java/io/legado/app/help/EventMessage.kt
  13. 13
      app/src/main/java/io/legado/app/help/LayoutManager.kt
  14. 6
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  15. 12
      app/src/main/java/io/legado/app/help/http/SSLHelper.kt
  16. 4
      app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
  17. 5
      app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
  18. 32
      app/src/main/java/io/legado/app/help/http/cronet/CronetUrlRequestCallback.kt
  19. 15
      app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt
  20. 3
      app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt
  21. 116
      app/src/main/java/io/legado/app/lib/icu4j/CharsetDetector.java
  22. 25
      app/src/main/java/io/legado/app/lib/icu4j/CharsetMatch.java
  23. 6
      app/src/main/java/io/legado/app/lib/icu4j/CharsetRecog_2022.java
  24. 38
      app/src/main/java/io/legado/app/lib/icu4j/CharsetRecog_sbcs.java
  25. 10
      app/src/main/java/io/legado/app/lib/icu4j/CharsetRecognizer.java
  26. 17
      app/src/main/java/io/legado/app/lib/theme/DrawableUtils.kt
  27. 22
      app/src/main/java/io/legado/app/lib/theme/NavigationViewUtils.kt
  28. 7
      app/src/main/java/io/legado/app/lib/theme/Selector.kt
  29. 38
      app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt
  30. 4
      app/src/main/java/io/legado/app/model/Debug.kt
  31. 20
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt
  32. 115
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt
  33. 8
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt
  34. 16
      app/src/main/java/io/legado/app/model/analyzeRule/RuleAnalyzer.kt
  35. 38
      app/src/main/java/io/legado/app/model/localBook/LocalBook.kt
  36. 28
      app/src/main/java/io/legado/app/model/localBook/UmdFile.kt
  37. 4
      app/src/main/java/io/legado/app/model/webBook/SearchBookModel.kt
  38. 5
      app/src/main/java/io/legado/app/service/CheckSourceService.kt
  39. 27
      app/src/main/java/io/legado/app/service/HttpReadAloudService.kt
  40. 6
      app/src/main/java/io/legado/app/ui/book/cache/CacheViewModel.kt
  41. 3
      app/src/main/java/io/legado/app/ui/book/read/config/TextFontWeightConverter.kt
  42. 9
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt
  43. 34
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/curl/CurlMesh.java
  44. 1
      app/src/main/java/io/legado/app/ui/book/read/page/provider/ZhLayout.kt
  45. 2
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchResult.kt
  46. 2
      app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugModel.kt
  47. 7
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt
  48. 4
      app/src/main/java/io/legado/app/ui/book/toc/BookmarkFragment.kt
  49. 2
      app/src/main/java/io/legado/app/ui/document/adapter/FileAdapter.kt
  50. 8
      app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt
  51. 1
      app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt
  52. 8
      app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt
  53. 2
      app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
  54. 3
      app/src/main/java/io/legado/app/ui/widget/prefs/EditTextPreference.kt
  55. 13
      app/src/main/java/io/legado/app/ui/widget/prefs/IconListPreference.kt
  56. 3
      app/src/main/java/io/legado/app/ui/widget/prefs/PreferenceCategory.kt
  57. 54
      app/src/main/java/io/legado/app/ui/widget/recycler/DragSelectTouchHelper.kt
  58. 8
      app/src/main/java/io/legado/app/ui/widget/recycler/ItemTouchCallback.kt
  59. 49
      app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt
  60. 4
      app/src/main/java/io/legado/app/ui/widget/text/BadgeView.kt
  61. 2
      app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt
  62. 8
      app/src/main/java/io/legado/app/utils/BitmapUtils.kt
  63. 10
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  64. 8
      app/src/main/java/io/legado/app/utils/IntExtensions.kt
  65. 58
      app/src/main/java/io/legado/app/utils/Snackbars.kt

@ -108,6 +108,9 @@ object BookController {
return returnData.setErrorMsg("参数url不能为空,请指定书籍地址") return returnData.setErrorMsg("参数url不能为空,请指定书籍地址")
} }
val chapterList = appDb.bookChapterDao.getChapterList(bookUrl) val chapterList = appDb.bookChapterDao.getChapterList(bookUrl)
if (chapterList.isEmpty()) {
return refreshToc(parameters)
}
return returnData.setData(chapterList) return returnData.setData(chapterList)
} }

@ -53,22 +53,27 @@ class ItemAnimation private constructor() {
companion object { companion object {
const val NONE: Int = 0x00000000 const val NONE: Int = 0x00000000
/** /**
* Use with [.openLoadAnimation] * Use with [.openLoadAnimation]
*/ */
const val FADE_IN: Int = 0x00000001 const val FADE_IN: Int = 0x00000001
/** /**
* Use with [.openLoadAnimation] * Use with [.openLoadAnimation]
*/ */
const val SCALE_IN: Int = 0x00000002 const val SCALE_IN: Int = 0x00000002
/** /**
* Use with [.openLoadAnimation] * Use with [.openLoadAnimation]
*/ */
const val BOTTOM_SLIDE_IN: Int = 0x00000003 const val BOTTOM_SLIDE_IN: Int = 0x00000003
/** /**
* Use with [.openLoadAnimation] * Use with [.openLoadAnimation]
*/ */
const val LEFT_SLIDE_IN: Int = 0x00000004 const val LEFT_SLIDE_IN: Int = 0x00000004
/** /**
* Use with [.openLoadAnimation] * Use with [.openLoadAnimation]
*/ */

@ -5,7 +5,8 @@ import android.animation.ObjectAnimator
import android.view.View import android.view.View
class AlphaInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_ALPHA_FROM) : BaseAnimation { class AlphaInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_ALPHA_FROM) :
BaseAnimation {
override fun getAnimators(view: View): Array<Animator> = override fun getAnimators(view: View): Array<Animator> =
arrayOf(ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)) arrayOf(ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f))

@ -5,7 +5,8 @@ import android.animation.ObjectAnimator
import android.view.View import android.view.View
class ScaleInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_SCALE_FROM) : BaseAnimation { class ScaleInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_SCALE_FROM) :
BaseAnimation {
override fun getAnimators(view: View): Array<Animator> { override fun getAnimators(view: View): Array<Animator> {
val scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f) val scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f)

@ -67,6 +67,7 @@ data class Book(
fun isEpub(): Boolean { fun isEpub(): Boolean {
return originName.endsWith(".epub", true) return originName.endsWith(".epub", true)
} }
fun isUmd(): Boolean { fun isUmd(): Boolean {
return originName.endsWith(".umd", true) return originName.endsWith(".umd", true)
} }

@ -50,7 +50,7 @@ data class BookSource(
@delegate:Ignore @delegate:Ignore
@IgnoredOnParcel @IgnoredOnParcel
val exploreKinds by lazy { val exploreKinds by lazy {
val exploreUrl = exploreUrl?.trim() ?: return@lazy emptyList() val exploreUrl = exploreUrl ?: return@lazy emptyList()
val kinds = arrayListOf<ExploreKind>() val kinds = arrayListOf<ExploreKind>()
var ruleStr = exploreUrl var ruleStr = exploreUrl
if (ruleStr.isNotBlank()) { if (ruleStr.isNotBlank()) {

@ -41,12 +41,12 @@ data class ReplaceRule(
return id.hashCode() return id.hashCode()
} }
fun isValid(): Boolean{ fun isValid(): Boolean {
if (TextUtils.isEmpty(pattern)){ if (TextUtils.isEmpty(pattern)) {
return false return false
} }
//判断正则表达式是否正确 //判断正则表达式是否正确
if (isRegex){ if (isRegex) {
try { try {
Pattern.compile(pattern) Pattern.compile(pattern)
} catch (ex: PatternSyntaxException) { } catch (ex: PatternSyntaxException) {

@ -38,7 +38,7 @@ data class SearchBook(
var time: Long = System.currentTimeMillis(), var time: Long = System.currentTimeMillis(),
var variable: String? = null, var variable: String? = null,
var originOrder: Int = 0 var originOrder: Int = 0
): Parcelable, BaseBook, Comparable<SearchBook> { ) : Parcelable, BaseBook, Comparable<SearchBook> {
@Ignore @Ignore
@IgnoredOnParcel @IgnoredOnParcel

@ -10,7 +10,7 @@ import splitties.init.appCtx
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val isGooglePlay = appCtx.channel == "google" val isGooglePlay = appCtx.channel == "google"
val isCronet= appCtx.channel=="cronet" val isCronet = appCtx.channel == "cronet"
var userAgent: String = getPrefUserAgent() var userAgent: String = getPrefUserAgent()
var isEInkMode = appCtx.getPrefString(PreferKey.themeMode) == "3" var isEInkMode = appCtx.getPrefString(PreferKey.themeMode) == "3"
var clickActionTL = appCtx.getPrefInt(PreferKey.clickActionTL, 2) var clickActionTL = appCtx.getPrefInt(PreferKey.clickActionTL, 2)

@ -23,7 +23,12 @@ class BlurTransformation(context: Context, private val radius: Int) : CenterCrop
private val rs: RenderScript = RenderScript.create(context) private val rs: RenderScript = RenderScript.create(context)
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap { override fun transform(
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
): Bitmap {
val transform = super.transform(pool, toTransform, outWidth, outHeight) val transform = super.transform(pool, toTransform, outWidth, outHeight)
//图片缩小1/2 //图片缩小1/2
val width = (min(outWidth, transform.width) / 2f).roundToInt() val width = (min(outWidth, transform.width) / 2f).roundToInt()

@ -190,7 +190,7 @@ object BookHelp {
} }
fun getContent(book: Book, bookChapter: BookChapter): String? { fun getContent(book: Book, bookChapter: BookChapter): String? {
if (book.isLocalTxt()||book.isUmd()) { if (book.isLocalTxt() || book.isUmd()) {
return LocalBook.getContext(book, bookChapter) return LocalBook.getContext(book, bookChapter)
} else if (book.isEpub() && !hasContent(book, bookChapter)) { } else if (book.isEpub() && !hasContent(book, bookChapter)) {
val string = LocalBook.getContext(book, bookChapter) val string = LocalBook.getContext(book, bookChapter)
@ -203,7 +203,7 @@ object BookHelp {
).writeText(it) ).writeText(it)
} }
return string return string
}else { } else {
val file = FileUtils.getFile( val file = FileUtils.getFile(
downloadDir, downloadDir,
cacheFolderName, cacheFolderName,
@ -346,7 +346,7 @@ object BookHelp {
chapterNamePattern1.matcher(chapterName1).takeIf { it.find() } chapterNamePattern1.matcher(chapterName1).takeIf { it.find() }
?: chapterNamePattern2.matcher(chapterName1).takeIf { it.find() } ?: chapterNamePattern2.matcher(chapterName1).takeIf { it.find() }
)?.group(1) )?.group(1)
?:"-1" ?: "-1"
) )
} }

@ -5,7 +5,7 @@ import android.text.TextUtils
@Suppress("unused") @Suppress("unused")
class EventMessage { class EventMessage {
var what: Int?=null var what: Int? = null
var tag: String? = null var tag: String? = null
var obj: Any? = null var obj: Any? = null

@ -44,10 +44,19 @@ object LayoutManager {
} }
fun grid(spanCount: Int, @Orientation orientation: Int, reverseLayout: Boolean): LayoutManagerFactory { fun grid(
spanCount: Int,
@Orientation orientation: Int,
reverseLayout: Boolean
): LayoutManagerFactory {
return object : LayoutManagerFactory { return object : LayoutManagerFactory {
override fun create(recyclerView: RecyclerView): RecyclerView.LayoutManager { override fun create(recyclerView: RecyclerView): RecyclerView.LayoutManager {
return GridLayoutManager(recyclerView.context, spanCount, orientation, reverseLayout) return GridLayoutManager(
recyclerView.context,
spanCount,
orientation,
reverseLayout
)
} }
} }
} }

@ -43,9 +43,9 @@ val okHttpClient: OkHttpClient by lazy {
.build() .build()
chain.proceed(request) chain.proceed(request)
}) })
if (AppConfig.isCronet){ if (AppConfig.isCronet) {
builder.addInterceptor(CronetInterceptor()) builder.addInterceptor(CronetInterceptor())
} }
builder.build() builder.build()

@ -79,7 +79,11 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书 * bksFile password -> 客户端使用bks证书校验服务端证书
* certificates -> 用含有服务端公钥的证书校验服务端证书 * certificates -> 用含有服务端公钥的证书校验服务端证书
*/ */
fun getSslSocketFactory(bksFile: InputStream, password: String, vararg certificates: InputStream): SSLParams? { fun getSslSocketFactory(
bksFile: InputStream,
password: String,
vararg certificates: InputStream
): SSLParams? {
return getSslSocketFactoryBase(null, bksFile, password, *certificates) return getSslSocketFactoryBase(null, bksFile, password, *certificates)
} }
@ -88,7 +92,11 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书 * bksFile password -> 客户端使用bks证书校验服务端证书
* X509TrustManager -> 如果需要自己校验那么可以自己实现相关校验如果不需要自己校验那么传null即可 * X509TrustManager -> 如果需要自己校验那么可以自己实现相关校验如果不需要自己校验那么传null即可
*/ */
fun getSslSocketFactory(bksFile: InputStream, password: String, trustManager: X509TrustManager): SSLParams? { fun getSslSocketFactory(
bksFile: InputStream,
password: String,
trustManager: X509TrustManager
): SSLParams? {
return getSslSocketFactoryBase(trustManager, bksFile, password) return getSslSocketFactoryBase(trustManager, bksFile, password)
} }

@ -40,7 +40,7 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest {
requestBuilder.addHeader("Cookie", cookie) requestBuilder.addHeader("Cookie", cookie)
} }
val headers: Headers = request.headers val headers: Headers = request.headers
headers.forEachIndexed { index, pair -> headers.forEachIndexed { index, _ ->
requestBuilder.addHeader(headers.name(index), headers.value(index)) requestBuilder.addHeader(headers.name(index), headers.value(index))
} }
@ -55,7 +55,7 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest {
requestBuilder.setUploadDataProvider( requestBuilder.setUploadDataProvider(
UploadDataProviders.create(buffer.readByteArray()), UploadDataProviders.create(buffer.readByteArray()),
executor executor
); )
} }

@ -1,6 +1,9 @@
package io.legado.app.help.http.cronet package io.legado.app.help.http.cronet
import okhttp3.* import okhttp3.Call
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.io.IOException import java.io.IOException
class CronetInterceptor : Interceptor { class CronetInterceptor : Interceptor {

@ -22,6 +22,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
eventListener: EventListener? = null, eventListener: EventListener? = null,
responseCallback: Callback? = null responseCallback: Callback? = null
) : UrlRequest.Callback() { ) : UrlRequest.Callback() {
private val eventListener: EventListener? private val eventListener: EventListener?
private val responseCallback: Callback? private val responseCallback: Callback?
private var followCount = 0 private var followCount = 0
@ -37,7 +38,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
if (mException != null) { if (mException != null) {
throw mException as IOException throw mException as IOException
} }
return mResponse return this.mResponse
} }
override fun onRedirectReceived( override fun onRedirectReceived(
@ -62,7 +63,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
} }
override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) { override fun onResponseStarted(request: UrlRequest, info: UrlResponseInfo) {
mResponse = responseFromResponse(mResponse, info) this.mResponse = responseFromResponse(this.mResponse, info)
// val sb: StringBuilder = StringBuilder(info.url).append("\r\n") // val sb: StringBuilder = StringBuilder(info.url).append("\r\n")
// sb.append("[Cached:").append(info.wasCached()).append("][StatusCode:") // sb.append("[Cached:").append(info.wasCached()).append("][StatusCode:")
// .append(info.httpStatusCode).append("][StatusText:").append(info.httpStatusText) // .append(info.httpStatusCode).append("][StatusText:").append(info.httpStatusText)
@ -74,7 +75,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
// } // }
// Log.e("Cronet", sb.toString()) // Log.e("Cronet", sb.toString())
if (eventListener != null) { if (eventListener != null) {
eventListener.responseHeadersEnd(mCall, mResponse) eventListener.responseHeadersEnd(mCall, this.mResponse)
eventListener.responseBodyStart(mCall) eventListener.responseBodyStart(mCall)
} }
request.read(ByteBuffer.allocateDirect(32 * 1024)) request.read(ByteBuffer.allocateDirect(32 * 1024))
@ -99,34 +100,43 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) { override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
eventListener?.responseBodyEnd(mCall, info.receivedByteCount) eventListener?.responseBodyEnd(mCall, info.receivedByteCount)
val contentType: MediaType? = (mResponse.header("content-type") val contentType: MediaType? = (this.mResponse.header("content-type")
?: "text/plain; charset=\"utf-8\"").toMediaTypeOrNull() ?: "text/plain; charset=\"utf-8\"").toMediaTypeOrNull()
val responseBody: ResponseBody = val responseBody: ResponseBody =
mBytesReceived.toByteArray().toResponseBody(contentType) mBytesReceived.toByteArray().toResponseBody(contentType)
val newRequest = originalRequest.newBuilder().url(info.url).build() val newRequest = originalRequest.newBuilder().url(info.url).build()
mResponse = mResponse.newBuilder().body(responseBody).request(newRequest).build() this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
mResponseCondition.open() mResponseCondition.open()
eventListener?.callEnd(mCall) eventListener?.callEnd(mCall)
if (responseCallback != null) { if (responseCallback != null) {
try { try {
responseCallback.onResponse(mCall, mResponse) responseCallback.onResponse(mCall, this.mResponse)
} catch (e: IOException) { } catch (e: IOException) {
// Pass? // Pass?
} }
} }
} }
override fun onFailed(request: UrlRequest, info: UrlResponseInfo, error: CronetException) { //UrlResponseInfo可能为null
val e = IOException("Cronet Exception Occurred", error) override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
Log.e(TAG, error.message.toString())
val msg = error.localizedMessage
val e = IOException(msg?.substring(msg.indexOf("net::")), error)
mException = e mException = e
mResponseCondition.open() mResponseCondition.open()
eventListener?.callFailed(mCall, e)
this.eventListener?.callFailed(mCall, e)
responseCallback?.onFailure(mCall, e) responseCallback?.onFailure(mCall, e)
} }
override fun onCanceled(request: UrlRequest, info: UrlResponseInfo) { override fun onCanceled(request: UrlRequest, info: UrlResponseInfo) {
mResponseCondition.open() mResponseCondition.open()
eventListener?.callEnd(mCall)
this.eventListener?.callEnd(mCall)
} }
companion object { companion object {
@ -194,7 +204,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
} }
init { init {
mResponse = Response.Builder() this.mResponse = Response.Builder()
.sentRequestAtMillis(System.currentTimeMillis()) .sentRequestAtMillis(System.currentTimeMillis())
.request(originalRequest) .request(originalRequest)
.protocol(Protocol.HTTP_1_0) .protocol(Protocol.HTTP_1_0)

@ -62,15 +62,24 @@ internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder<Ale
builder.setPositiveButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } builder.setPositiveButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) }
} }
override fun positiveButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { override fun positiveButton(
buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) }
} }
override fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)?) { override fun negativeButton(
buttonText: String,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNegativeButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } builder.setNegativeButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) }
} }
override fun negativeButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { override fun negativeButton(
buttonTextResource: Int,
onClicked: ((dialog: DialogInterface) -> Unit)?
) {
builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) }
} }

@ -53,7 +53,8 @@ fun Context.alert(
} }
inline fun Fragment.alert(noinline init: AlertBuilder<DialogInterface>.() -> Unit) = requireContext().alert(init) inline fun Fragment.alert(noinline init: AlertBuilder<DialogInterface>.() -> Unit) =
requireContext().alert(init)
fun Context.alert(init: AlertBuilder<AlertDialog>.() -> Unit): AlertBuilder<AlertDialog> = fun Context.alert(init: AlertBuilder<AlertDialog>.() -> Unit): AlertBuilder<AlertDialog> =
AndroidAlertBuilder(this).apply { init() } AndroidAlertBuilder(this).apply { init() }

@ -52,7 +52,7 @@ public class CharsetDetector {
// wants the data, and doesn't care about a char set name. // wants the data, and doesn't care about a char set name.
/** /**
* Constructor * Constructor
* *
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
@ -61,18 +61,17 @@ public class CharsetDetector {
/** /**
* Set the declared encoding for charset detection. * Set the declared encoding for charset detection.
* The declared encoding of an input text is an encoding obtained * The declared encoding of an input text is an encoding obtained
* from an http header or xml declaration or similar source that * from an http header or xml declaration or similar source that
* can be provided as additional information to the charset detector. * can be provided as additional information to the charset detector.
* A match between a declared encoding and a possible detected encoding * A match between a declared encoding and a possible detected encoding
* will raise the quality of that detected encoding by a small delta, * will raise the quality of that detected encoding by a small delta,
* and will also appear as a "reason" for the match. * and will also appear as a "reason" for the match.
* <p> * <p>
* A declared encoding that is incompatible with the input data being * A declared encoding that is incompatible with the input data being
* analyzed will not be added to the list of possible encodings. * analyzed will not be added to the list of possible encodings.
* *
* @param encoding The declared encoding * @param encoding The declared encoding
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public CharsetDetector setDeclaredEncoding(String encoding) { public CharsetDetector setDeclaredEncoding(String encoding) {
@ -84,9 +83,7 @@ public class CharsetDetector {
* Set the input text (byte) data whose charset is to be detected. * Set the input text (byte) data whose charset is to be detected.
* *
* @param in the input text of unknown encoding * @param in the input text of unknown encoding
*
* @return This CharsetDetector * @return This CharsetDetector
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public CharsetDetector setText(byte[] in) { public CharsetDetector setText(byte[] in) {
@ -100,17 +97,15 @@ public class CharsetDetector {
/** /**
* Set the input text (byte) data whose charset is to be detected. * Set the input text (byte) data whose charset is to be detected.
* <p> * <p>
* The input stream that supplies the character data must have markSupported() * The input stream that supplies the character data must have markSupported()
* == true; the charset detection process will read a small amount of data, * == true; the charset detection process will read a small amount of data,
* then return the stream to its original position via * then return the stream to its original position via
* the InputStream.reset() operation. The exact amount that will * the InputStream.reset() operation. The exact amount that will
* be read depends on the characteristics of the data itself. * be read depends on the characteristics of the data itself.
* *
* @param in the input text of unknown encoding * @param in the input text of unknown encoding
*
* @return This CharsetDetector * @return This CharsetDetector
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
@ -139,21 +134,20 @@ public class CharsetDetector {
/** /**
* Return the charset that best matches the supplied input data. * Return the charset that best matches the supplied input data.
* * <p>
* Note though, that because the detection * Note though, that because the detection
* only looks at the start of the input data, * only looks at the start of the input data,
* there is a possibility that the returned charset will fail to handle * there is a possibility that the returned charset will fail to handle
* the full set of input data. * the full set of input data.
* <p> * p>
* Raise an exception if * aise an exception if
* <ul> * <ul>
* <li>no charset appears to match the data.</li> * <li>no charset appears to match the data.</li>
* <li>no input text has been provided</li> * <li>no input text has been provided</li>
* </ul> * </ul>
* *
* @return a CharsetMatch object representing the best matching charset, or * @return a CharsetMatch object representing the best matching charset, or
* <code>null</code> if there are no matches. * <code>null</code> if there are no matches.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public CharsetMatch detect() { public CharsetMatch detect() {
@ -171,18 +165,17 @@ public class CharsetDetector {
} }
/** /**
* Return an array of all charsets that appear to be plausible * Return an array of all charsets that appear to be plausible
* matches with the input data. The array is ordered with the * matches with the input data. The array is ordered with the
* best quality match first. * best quality match first.
* <p> * <p>
* Raise an exception if * aise an exception if
* <ul> * <ul>
* <li>no charsets appear to match the input data.</li> * <li>no charsets appear to match the input data.</li>
* <li>no input text has been provided</li> * <li>no input text has been provided</li>
* </ul> * </ul>
* *
* @return An array of CharsetMatch objects representing possibly matching charsets. * @return An array of CharsetMatch objects representing possibly matching charsets.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public CharsetMatch[] detectAll() { public CharsetMatch[] detectAll() {
@ -215,21 +208,19 @@ public class CharsetDetector {
* to access the converted input data. * to access the converted input data.
* <p> * <p>
* This is a convenience method that is equivalent to * This is a convenience method that is equivalent to
* <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getReader();</code> * <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getReader();</code>
* <p>
* For the input stream that supplies the character data, markSupported()
* must be true; the charset detection will read a small amount of data,
* then return the stream to its original position via
* the InputStream.reset() operation. The exact amount that will
* be read depends on the characteristics of the data itself.
* <p> * <p>
* For the input stream that supplies the character data, markSupported()
* must be true; the charset detection will read a small amount of data,
* then return the stream to its original position via
* the InputStream.reset() operation. The exact amount that will
* be read depends on the characteristics of the data itself.
*<p>
* Raise an exception if no charsets appear to match the input data. * Raise an exception if no charsets appear to match the input data.
* *
* @param in The source of the byte data in the unknown charset. * @param in The source of the byte data in the unknown charset.
* * @param declaredEncoding A declared encoding for the data, if available,
* @param declaredEncoding A declared encoding for the data, if available, * or null or an empty string if none is available.
* or null or an empty string if none is available.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public Reader getReader(InputStream in, String declaredEncoding) { public Reader getReader(InputStream in, String declaredEncoding) {
@ -255,15 +246,13 @@ public class CharsetDetector {
* containing the converted input data. * containing the converted input data.
* <p> * <p>
* This is a convenience method that is equivalent to * This is a convenience method that is equivalent to
* <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getString();</code> * <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getString();</code>
*<p> * <p>
* Raise an exception if no charsets appear to match the input data. * Raise an exception if no charsets appear to match the input data.
* *
* @param in The source of the byte data in the unknown charset. * @param in The source of the byte data in the unknown charset.
* * @param declaredEncoding A declared encoding for the data, if available,
* @param declaredEncoding A declared encoding for the data, if available, * or null or an empty string if none is available.
* or null or an empty string if none is available.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public String getString(byte[] in, String declaredEncoding) { public String getString(byte[] in, String declaredEncoding) {
@ -297,7 +286,6 @@ public class CharsetDetector {
* *
* @return an array of the names of all charsets supported by * @return an array of the names of all charsets supported by
* <code>CharsetDetector</code> class. * <code>CharsetDetector</code> class.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public static String[] getAllDetectableCharsets() { public static String[] getAllDetectableCharsets() {
@ -312,10 +300,8 @@ public class CharsetDetector {
* Test whether or not input filtering is enabled. * Test whether or not input filtering is enabled.
* *
* @return <code>true</code> if input text will be filtered. * @return <code>true</code> if input text will be filtered.
*
* @see #enableInputFilter
*
* @stable ICU 3.4 * @stable ICU 3.4
* @see #enableInputFilter
*/ */
public boolean inputFilterEnabled() { public boolean inputFilterEnabled() {
return fStripTags; return fStripTags;
@ -327,9 +313,7 @@ public class CharsetDetector {
* before detection. * before detection.
* *
* @param filter <code>true</code> to enable input text filtering. * @param filter <code>true</code> to enable input text filtering.
*
* @return The previous setting. * @return The previous setting.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public boolean enableInputFilter(boolean filter) { public boolean enableInputFilter(boolean filter) {
@ -517,7 +501,6 @@ public class CharsetDetector {
* *
* @return an array of the names of charsets that can be recognized by this CharsetDetector * @return an array of the names of charsets that can be recognized by this CharsetDetector
* instance. * instance.
*
* @internal * @internal
* @deprecated This API is ICU internal only. * @deprecated This API is ICU internal only.
*/ */
@ -540,12 +523,11 @@ public class CharsetDetector {
* {@link #getAllDetectableCharsets()}. * {@link #getAllDetectableCharsets()}.
* *
* @param encoding the name of charset encoding. * @param encoding the name of charset encoding.
* @param enabled <code>true</code> to enable, or <code>false</code> to disable the * @param enabled <code>true</code> to enable, or <code>false</code> to disable the
* charset encoding. * charset encoding.
* @return A reference to this <code>CharsetDetector</code>. * @return A reference to this <code>CharsetDetector</code>.
* @throws IllegalArgumentException when the name of charset encoding is * @throws IllegalArgumentException when the name of charset encoding is
* not supported. * not supported.
*
* @internal * @internal
* @deprecated This API is ICU internal only. * @deprecated This API is ICU internal only.
*/ */

@ -42,7 +42,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* the InputStream and create InputStreamReaders itself, based on the charset name. * the InputStream and create InputStreamReaders itself, based on the charset name.
* *
* @return the Reader for the Unicode character data. * @return the Reader for the Unicode character data.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public Reader getReader() { public Reader getReader() {
@ -65,7 +64,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* to the original byte data supplied to the Charset detect operation. * to the original byte data supplied to the Charset detect operation.
* *
* @return a String created from the converted input data. * @return a String created from the converted input data.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public String getString() throws java.io.IOException { public String getString() throws java.io.IOException {
@ -84,7 +82,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* source of the data is an input stream, or -1 for * source of the data is an input stream, or -1 for
* unlimited length. * unlimited length.
* @return a String created from the converted input data. * @return a String created from the converted input data.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public String getString(int maxLength) throws java.io.IOException { public String getString(int maxLength) throws java.io.IOException {
@ -128,7 +125,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* charset. * charset.
* *
* @return the confidence in the charset match * @return the confidence in the charset match
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public int getConfidence() { public int getConfidence() {
@ -143,12 +139,10 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* charsets that are registered with the IANA charset registry, * charsets that are registered with the IANA charset registry,
* this is the MIME-preferred registerd name. * this is the MIME-preferred registerd name.
* *
* @see java.nio.charset.Charset
* @see java.io.InputStreamReader
*
* @return The name of the charset. * @return The name of the charset.
*
* @stable ICU 3.4 * @stable ICU 3.4
* @see java.nio.charset.Charset
* @see java.io.InputStreamReader
*/ */
public String getName() { public String getName() {
return fCharsetName; return fCharsetName;
@ -158,7 +152,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* Get the ISO code for the language of the detected charset. * Get the ISO code for the language of the detected charset.
* *
* @return The ISO code for the language or <code>null</code> if the language cannot be determined. * @return The ISO code for the language or <code>null</code> if the language cannot be determined.
*
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public String getLanguage() { public String getLanguage() {
@ -168,13 +161,13 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
/** /**
* Compare to other CharsetMatch objects. * Compare to other CharsetMatch objects.
* Comparison is based on the match confidence value, which * Comparison is based on the match confidence value, which
* allows CharsetDetector.detectAll() to order its results. * allows CharsetDetector.detectAll() to order its results.
* *
* @param other the CharsetMatch object to compare against. * @param other the CharsetMatch object to compare against.
* @return a negative integer, zero, or a positive integer as the * @return a negative integer, zero, or a positive integer as the
* confidence level of this CharsetMatch * confidence level of this CharsetMatch
* is less than, equal to, or greater than that of * is less than, equal to, or greater than that of
* the argument. * the argument.
* @throws ClassCastException if the argument is not a CharsetMatch. * @throws ClassCastException if the argument is not a CharsetMatch.
* @stable ICU 4.4 * @stable ICU 4.4
*/ */
@ -233,7 +226,7 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
// //
// Private Data // Private Data
// //
private int fConfidence; private final int fConfidence;
private byte[] fRawInput = null; // Original, untouched input bytes. private byte[] fRawInput = null; // Original, untouched input bytes.
// If user gave us a byte array, this is it. // If user gave us a byte array, this is it.
private int fRawLength; // Length of data in fRawInput array. private int fRawLength; // Length of data in fRawInput array.
@ -241,8 +234,8 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
private InputStream fInputStream = null; // User's input stream, or null if the user private InputStream fInputStream = null; // User's input stream, or null if the user
// gave us a byte array. // gave us a byte array.
private String fCharsetName; // The name of the charset this CharsetMatch private final String fCharsetName; // The name of the charset this CharsetMatch
// represents. Filled in by the recognizer. // represents. Filled in by the recognizer.
private String fLang; // The language, if one was determined by private final String fLang; // The language, if one was determined by
// the recognizer during the detect operation. // the recognizer during the detect operation.
} }

@ -95,7 +95,7 @@ abstract class CharsetRecog_2022 extends CharsetRecognizer {
static class CharsetRecog_2022JP extends CharsetRecog_2022 { static class CharsetRecog_2022JP extends CharsetRecog_2022 {
private byte[][] escapeSequences = { private final byte[][] escapeSequences = {
{0x1b, 0x24, 0x28, 0x43}, // KS X 1001:1992 {0x1b, 0x24, 0x28, 0x43}, // KS X 1001:1992
{0x1b, 0x24, 0x28, 0x44}, // JIS X 212-1990 {0x1b, 0x24, 0x28, 0x44}, // JIS X 212-1990
{0x1b, 0x24, 0x40}, // JIS C 6226-1978 {0x1b, 0x24, 0x40}, // JIS C 6226-1978
@ -123,7 +123,7 @@ abstract class CharsetRecog_2022 extends CharsetRecognizer {
} }
static class CharsetRecog_2022KR extends CharsetRecog_2022 { static class CharsetRecog_2022KR extends CharsetRecog_2022 {
private byte[][] escapeSequences = { private final byte[][] escapeSequences = {
{0x1b, 0x24, 0x29, 0x43} {0x1b, 0x24, 0x29, 0x43}
}; };
@ -140,7 +140,7 @@ abstract class CharsetRecog_2022 extends CharsetRecognizer {
} }
static class CharsetRecog_2022CN extends CharsetRecog_2022 { static class CharsetRecog_2022CN extends CharsetRecog_2022 {
private byte[][] escapeSequences = { private final byte[][] escapeSequences = {
{0x1b, 0x24, 0x29, 0x41}, // GB 2312-80 {0x1b, 0x24, 0x29, 0x41}, // GB 2312-80
{0x1b, 0x24, 0x29, 0x47}, // CNS 11643-1992 Plane 1 {0x1b, 0x24, 0x29, 0x47}, // CNS 11643-1992 Plane 1
{0x1b, 0x24, 0x2A, 0x48}, // CNS 11643-1992 Plane 2 {0x1b, 0x24, 0x2A, 0x48}, // CNS 11643-1992 Plane 2

@ -29,7 +29,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
protected int byteIndex = 0; protected int byteIndex = 0;
private int ngram = 0; private int ngram = 0;
private int[] ngramList; private final int[] ngramList;
protected byte[] byteMap; protected byte[] byteMap;
private int ngramCount; private int ngramCount;
@ -315,7 +315,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}; };
private static NGramsPlusLang[] ngrams_8859_1 = new NGramsPlusLang[]{ private static final NGramsPlusLang[] ngrams_8859_1 = new NGramsPlusLang[]{
new NGramsPlusLang( new NGramsPlusLang(
"da", "da",
new int[]{ new int[]{
@ -467,7 +467,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
(byte) 0xF8, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0x20, (byte) 0xF8, (byte) 0xF9, (byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD, (byte) 0xFE, (byte) 0x20,
}; };
private static NGramsPlusLang[] ngrams_8859_2 = new NGramsPlusLang[]{ private static final NGramsPlusLang[] ngrams_8859_2 = new NGramsPlusLang[]{
new NGramsPlusLang( new NGramsPlusLang(
"cs", "cs",
new int[]{ new int[]{
@ -568,7 +568,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_5_ru extends CharsetRecog_8859_5 { static class CharsetRecog_8859_5_ru extends CharsetRecog_8859_5 {
private static int[] ngrams = { private static final int[] ngrams = {
0x20D220, 0x20D2DE, 0x20D4DE, 0x20D7D0, 0x20D820, 0x20DAD0, 0x20DADE, 0x20DDD0, 0x20DDD5, 0x20DED1, 0x20DFDE, 0x20DFE0, 0x20E0D0, 0x20E1DE, 0x20E1E2, 0x20E2DE, 0x20D220, 0x20D2DE, 0x20D4DE, 0x20D7D0, 0x20D820, 0x20DAD0, 0x20DADE, 0x20DDD0, 0x20DDD5, 0x20DED1, 0x20DFDE, 0x20DFE0, 0x20E0D0, 0x20E1DE, 0x20E1E2, 0x20E2DE,
0x20E7E2, 0x20EDE2, 0xD0DDD8, 0xD0E2EC, 0xD3DE20, 0xD5DBEC, 0xD5DDD8, 0xD5E1E2, 0xD5E220, 0xD820DF, 0xD8D520, 0xD8D820, 0xD8EF20, 0xDBD5DD, 0xDBD820, 0xDBECDD, 0x20E7E2, 0x20EDE2, 0xD0DDD8, 0xD0E2EC, 0xD3DE20, 0xD5DBEC, 0xD5DDD8, 0xD5E1E2, 0xD5E220, 0xD820DF, 0xD8D520, 0xD8D820, 0xD8EF20, 0xDBD5DD, 0xDBD820, 0xDBECDD,
0xDDD020, 0xDDD520, 0xDDD8D5, 0xDDD8EF, 0xDDDE20, 0xDDDED2, 0xDE20D2, 0xDE20DF, 0xDE20E1, 0xDED220, 0xDED2D0, 0xDED3DE, 0xDED920, 0xDEDBEC, 0xDEDC20, 0xDEE1E2, 0xDDD020, 0xDDD520, 0xDDD8D5, 0xDDD8EF, 0xDDDE20, 0xDDDED2, 0xDE20D2, 0xDE20DF, 0xDE20E1, 0xDED220, 0xDED2D0, 0xDED3DE, 0xDED920, 0xDEDBEC, 0xDEDC20, 0xDEE1E2,
@ -630,7 +630,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_6_ar extends CharsetRecog_8859_6 { static class CharsetRecog_8859_6_ar extends CharsetRecog_8859_6 {
private static int[] ngrams = { private static final int[] ngrams = {
0x20C7E4, 0x20C7E6, 0x20C8C7, 0x20D9E4, 0x20E1EA, 0x20E4E4, 0x20E5E6, 0x20E8C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E420, 0xC7E4C3, 0xC7E4C7, 0xC7E4C8, 0x20C7E4, 0x20C7E6, 0x20C8C7, 0x20D9E4, 0x20E1EA, 0x20E4E4, 0x20E5E6, 0x20E8C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E420, 0xC7E4C3, 0xC7E4C7, 0xC7E4C8,
0xC7E4CA, 0xC7E4CC, 0xC7E4CD, 0xC7E4CF, 0xC7E4D3, 0xC7E4D9, 0xC7E4E2, 0xC7E4E5, 0xC7E4E8, 0xC7E4EA, 0xC7E520, 0xC7E620, 0xC7E6CA, 0xC820C7, 0xC920C7, 0xC920E1, 0xC7E4CA, 0xC7E4CC, 0xC7E4CD, 0xC7E4CF, 0xC7E4D3, 0xC7E4D9, 0xC7E4E2, 0xC7E4E5, 0xC7E4E8, 0xC7E4EA, 0xC7E520, 0xC7E620, 0xC7E6CA, 0xC820C7, 0xC920C7, 0xC920E1,
0xC920E4, 0xC920E5, 0xC920E8, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xD920C7, 0xD9E4E9, 0xE1EA20, 0xE420C7, 0xE4C920, 0xE4E920, 0xE4EA20, 0xC920E4, 0xC920E5, 0xC920E8, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xD920C7, 0xD9E4E9, 0xE1EA20, 0xE420C7, 0xE4C920, 0xE4E920, 0xE4EA20,
@ -692,7 +692,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_7_el extends CharsetRecog_8859_7 { static class CharsetRecog_8859_7_el extends CharsetRecog_8859_7 {
private static int[] ngrams = { private static final int[] ngrams = {
0x20E1ED, 0x20E1F0, 0x20E3E9, 0x20E4E9, 0x20E5F0, 0x20E720, 0x20EAE1, 0x20ECE5, 0x20EDE1, 0x20EF20, 0x20F0E1, 0x20F0EF, 0x20F0F1, 0x20F3F4, 0x20F3F5, 0x20F4E7, 0x20E1ED, 0x20E1F0, 0x20E3E9, 0x20E4E9, 0x20E5F0, 0x20E720, 0x20EAE1, 0x20ECE5, 0x20EDE1, 0x20EF20, 0x20F0E1, 0x20F0EF, 0x20F0F1, 0x20F3F4, 0x20F3F5, 0x20F4E7,
0x20F4EF, 0xDFE120, 0xE120E1, 0xE120F4, 0xE1E920, 0xE1ED20, 0xE1F0FC, 0xE1F220, 0xE3E9E1, 0xE5E920, 0xE5F220, 0xE720F4, 0xE7ED20, 0xE7F220, 0xE920F4, 0xE9E120, 0x20F4EF, 0xDFE120, 0xE120E1, 0xE120F4, 0xE1E920, 0xE1ED20, 0xE1F0FC, 0xE1F220, 0xE3E9E1, 0xE5E920, 0xE5F220, 0xE720F4, 0xE7ED20, 0xE7F220, 0xE920F4, 0xE9E120,
0xE9EADE, 0xE9F220, 0xEAE1E9, 0xEAE1F4, 0xECE520, 0xED20E1, 0xED20E5, 0xED20F0, 0xEDE120, 0xEFF220, 0xEFF520, 0xF0EFF5, 0xF0F1EF, 0xF0FC20, 0xF220E1, 0xF220E5, 0xE9EADE, 0xE9F220, 0xEAE1E9, 0xEAE1F4, 0xECE520, 0xED20E1, 0xED20E5, 0xED20F0, 0xEDE120, 0xEFF220, 0xEFF520, 0xF0EFF5, 0xF0F1EF, 0xF0FC20, 0xF220E1, 0xF220E5,
@ -755,7 +755,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_8_I_he extends CharsetRecog_8859_8 { static class CharsetRecog_8859_8_I_he extends CharsetRecog_8859_8 {
private static int[] ngrams = { private static final int[] ngrams = {
0x20E0E5, 0x20E0E7, 0x20E0E9, 0x20E0FA, 0x20E1E9, 0x20E1EE, 0x20E4E0, 0x20E4E5, 0x20E4E9, 0x20E4EE, 0x20E4F2, 0x20E4F9, 0x20E4FA, 0x20ECE0, 0x20ECE4, 0x20EEE0, 0x20E0E5, 0x20E0E7, 0x20E0E9, 0x20E0FA, 0x20E1E9, 0x20E1EE, 0x20E4E0, 0x20E4E5, 0x20E4E9, 0x20E4EE, 0x20E4F2, 0x20E4F9, 0x20E4FA, 0x20ECE0, 0x20ECE4, 0x20EEE0,
0x20F2EC, 0x20F9EC, 0xE0FA20, 0xE420E0, 0xE420E1, 0xE420E4, 0xE420EC, 0xE420EE, 0xE420F9, 0xE4E5E0, 0xE5E020, 0xE5ED20, 0xE5EF20, 0xE5F820, 0xE5FA20, 0xE920E4, 0x20F2EC, 0x20F9EC, 0xE0FA20, 0xE420E0, 0xE420E1, 0xE420E4, 0xE420EC, 0xE420EE, 0xE420F9, 0xE4E5E0, 0xE5E020, 0xE5ED20, 0xE5EF20, 0xE5F820, 0xE5FA20, 0xE920E4,
0xE9E420, 0xE9E5FA, 0xE9E9ED, 0xE9ED20, 0xE9EF20, 0xE9F820, 0xE9FA20, 0xEC20E0, 0xEC20E4, 0xECE020, 0xECE420, 0xED20E0, 0xED20E1, 0xED20E4, 0xED20EC, 0xED20EE, 0xE9E420, 0xE9E5FA, 0xE9E9ED, 0xE9ED20, 0xE9EF20, 0xE9F820, 0xE9FA20, 0xEC20E0, 0xEC20E4, 0xECE020, 0xECE420, 0xED20E0, 0xED20E1, 0xED20E4, 0xED20EC, 0xED20EE,
@ -781,7 +781,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_8_he extends CharsetRecog_8859_8 { static class CharsetRecog_8859_8_he extends CharsetRecog_8859_8 {
private static int[] ngrams = { private static final int[] ngrams = {
0x20E0E5, 0x20E0EC, 0x20E4E9, 0x20E4EC, 0x20E4EE, 0x20E4F0, 0x20E9F0, 0x20ECF2, 0x20ECF9, 0x20EDE5, 0x20EDE9, 0x20EFE5, 0x20EFE9, 0x20F8E5, 0x20F8E9, 0x20FAE0, 0x20E0E5, 0x20E0EC, 0x20E4E9, 0x20E4EC, 0x20E4EE, 0x20E4F0, 0x20E9F0, 0x20ECF2, 0x20ECF9, 0x20EDE5, 0x20EDE9, 0x20EFE5, 0x20EFE9, 0x20F8E5, 0x20F8E9, 0x20FAE0,
0x20FAE5, 0x20FAE9, 0xE020E4, 0xE020EC, 0xE020ED, 0xE020FA, 0xE0E420, 0xE0E5E4, 0xE0EC20, 0xE0EE20, 0xE120E4, 0xE120ED, 0xE120FA, 0xE420E4, 0xE420E9, 0xE420EC, 0x20FAE5, 0x20FAE9, 0xE020E4, 0xE020EC, 0xE020ED, 0xE020FA, 0xE0E420, 0xE0E5E4, 0xE0EC20, 0xE0EE20, 0xE120E4, 0xE120ED, 0xE120FA, 0xE420E4, 0xE420E9, 0xE420EC,
0xE420ED, 0xE420EF, 0xE420F8, 0xE420FA, 0xE4EC20, 0xE5E020, 0xE5E420, 0xE7E020, 0xE9E020, 0xE9E120, 0xE9E420, 0xEC20E4, 0xEC20ED, 0xEC20FA, 0xECF220, 0xECF920, 0xE420ED, 0xE420EF, 0xE420F8, 0xE420FA, 0xE4EC20, 0xE5E020, 0xE5E420, 0xE7E020, 0xE9E020, 0xE9E120, 0xE9E420, 0xEC20E4, 0xEC20ED, 0xEC20FA, 0xECF220, 0xECF920,
@ -845,7 +845,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_8859_9_tr extends CharsetRecog_8859_9 { static class CharsetRecog_8859_9_tr extends CharsetRecog_8859_9 {
private static int[] ngrams = { private static final int[] ngrams = {
0x206261, 0x206269, 0x206275, 0x206461, 0x206465, 0x206765, 0x206861, 0x20696C, 0x206B61, 0x206B6F, 0x206D61, 0x206F6C, 0x207361, 0x207461, 0x207665, 0x207961, 0x206261, 0x206269, 0x206275, 0x206461, 0x206465, 0x206765, 0x206861, 0x20696C, 0x206B61, 0x206B6F, 0x206D61, 0x206F6C, 0x207361, 0x207461, 0x207665, 0x207961,
0x612062, 0x616B20, 0x616C61, 0x616D61, 0x616E20, 0x616EFD, 0x617220, 0x617261, 0x6172FD, 0x6173FD, 0x617961, 0x626972, 0x646120, 0x646520, 0x646920, 0x652062, 0x612062, 0x616B20, 0x616C61, 0x616D61, 0x616E20, 0x616EFD, 0x617220, 0x617261, 0x6172FD, 0x6173FD, 0x617961, 0x626972, 0x646120, 0x646520, 0x646920, 0x652062,
0x65206B, 0x656469, 0x656E20, 0x657220, 0x657269, 0x657369, 0x696C65, 0x696E20, 0x696E69, 0x697220, 0x6C616E, 0x6C6172, 0x6C6520, 0x6C6572, 0x6E2061, 0x6E2062, 0x65206B, 0x656469, 0x656E20, 0x657220, 0x657269, 0x657369, 0x696C65, 0x696E20, 0x696E69, 0x697220, 0x6C616E, 0x6C6172, 0x6C6520, 0x6C6572, 0x6E2061, 0x6E2062,
@ -866,14 +866,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_windows_1251 extends CharsetRecog_sbcs { static class CharsetRecog_windows_1251 extends CharsetRecog_sbcs {
private static int[] ngrams = { private static final int[] ngrams = {
0x20E220, 0x20E2EE, 0x20E4EE, 0x20E7E0, 0x20E820, 0x20EAE0, 0x20EAEE, 0x20EDE0, 0x20EDE5, 0x20EEE1, 0x20EFEE, 0x20EFF0, 0x20F0E0, 0x20F1EE, 0x20F1F2, 0x20F2EE, 0x20E220, 0x20E2EE, 0x20E4EE, 0x20E7E0, 0x20E820, 0x20EAE0, 0x20EAEE, 0x20EDE0, 0x20EDE5, 0x20EEE1, 0x20EFEE, 0x20EFF0, 0x20F0E0, 0x20F1EE, 0x20F1F2, 0x20F2EE,
0x20F7F2, 0x20FDF2, 0xE0EDE8, 0xE0F2FC, 0xE3EE20, 0xE5EBFC, 0xE5EDE8, 0xE5F1F2, 0xE5F220, 0xE820EF, 0xE8E520, 0xE8E820, 0xE8FF20, 0xEBE5ED, 0xEBE820, 0xEBFCED, 0x20F7F2, 0x20FDF2, 0xE0EDE8, 0xE0F2FC, 0xE3EE20, 0xE5EBFC, 0xE5EDE8, 0xE5F1F2, 0xE5F220, 0xE820EF, 0xE8E520, 0xE8E820, 0xE8FF20, 0xEBE5ED, 0xEBE820, 0xEBFCED,
0xEDE020, 0xEDE520, 0xEDE8E5, 0xEDE8FF, 0xEDEE20, 0xEDEEE2, 0xEE20E2, 0xEE20EF, 0xEE20F1, 0xEEE220, 0xEEE2E0, 0xEEE3EE, 0xEEE920, 0xEEEBFC, 0xEEEC20, 0xEEF1F2, 0xEDE020, 0xEDE520, 0xEDE8E5, 0xEDE8FF, 0xEDEE20, 0xEDEEE2, 0xEE20E2, 0xEE20EF, 0xEE20F1, 0xEEE220, 0xEEE2E0, 0xEEE3EE, 0xEEE920, 0xEEEBFC, 0xEEEC20, 0xEEF1F2,
0xEFEEEB, 0xEFF0E5, 0xEFF0E8, 0xEFF0EE, 0xF0E0E2, 0xF0E5E4, 0xF1F2E0, 0xF1F2E2, 0xF1F2E8, 0xF1FF20, 0xF2E5EB, 0xF2EE20, 0xF2EEF0, 0xF2FC20, 0xF7F2EE, 0xFBF520, 0xEFEEEB, 0xEFF0E5, 0xEFF0E8, 0xEFF0EE, 0xF0E0E2, 0xF0E5E4, 0xF1F2E0, 0xF1F2E2, 0xF1F2E8, 0xF1FF20, 0xF2E5EB, 0xF2EE20, 0xF2EEF0, 0xF2FC20, 0xF7F2EE, 0xFBF520,
}; };
private static byte[] byteMap = { private static final byte[] byteMap = {
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
@ -926,14 +926,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_windows_1256 extends CharsetRecog_sbcs { static class CharsetRecog_windows_1256 extends CharsetRecog_sbcs {
private static int[] ngrams = { private static final int[] ngrams = {
0x20C7E1, 0x20C7E4, 0x20C8C7, 0x20DAE1, 0x20DDED, 0x20E1E1, 0x20E3E4, 0x20E6C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E120, 0xC7E1C3, 0xC7E1C7, 0xC7E1C8, 0x20C7E1, 0x20C7E4, 0x20C8C7, 0x20DAE1, 0x20DDED, 0x20E1E1, 0x20E3E4, 0x20E6C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E120, 0xC7E1C3, 0xC7E1C7, 0xC7E1C8,
0xC7E1CA, 0xC7E1CC, 0xC7E1CD, 0xC7E1CF, 0xC7E1D3, 0xC7E1DA, 0xC7E1DE, 0xC7E1E3, 0xC7E1E6, 0xC7E1ED, 0xC7E320, 0xC7E420, 0xC7E4CA, 0xC820C7, 0xC920C7, 0xC920DD, 0xC7E1CA, 0xC7E1CC, 0xC7E1CD, 0xC7E1CF, 0xC7E1D3, 0xC7E1DA, 0xC7E1DE, 0xC7E1E3, 0xC7E1E6, 0xC7E1ED, 0xC7E320, 0xC7E420, 0xC7E4CA, 0xC820C7, 0xC920C7, 0xC920DD,
0xC920E1, 0xC920E3, 0xC920E6, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xDA20C7, 0xDAE1EC, 0xDDED20, 0xE120C7, 0xE1C920, 0xE1EC20, 0xE1ED20, 0xC920E1, 0xC920E3, 0xC920E6, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xDA20C7, 0xDAE1EC, 0xDDED20, 0xE120C7, 0xE1C920, 0xE1EC20, 0xE1ED20,
0xE320C7, 0xE3C720, 0xE3C920, 0xE3E420, 0xE420C7, 0xE520C7, 0xE5C720, 0xE6C7E1, 0xE6E420, 0xEC20C7, 0xED20C7, 0xED20E3, 0xED20E6, 0xEDC920, 0xEDD120, 0xEDE420, 0xE320C7, 0xE3C720, 0xE3C920, 0xE3E420, 0xE420C7, 0xE520C7, 0xE5C720, 0xE6C7E1, 0xE6E420, 0xEC20C7, 0xED20C7, 0xED20E3, 0xED20E6, 0xEDC920, 0xEDD120, 0xEDE420,
}; };
private static byte[] byteMap = { private static final byte[] byteMap = {
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
@ -986,14 +986,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_KOI8_R extends CharsetRecog_sbcs { static class CharsetRecog_KOI8_R extends CharsetRecog_sbcs {
private static int[] ngrams = { private static final int[] ngrams = {
0x20C4CF, 0x20C920, 0x20CBC1, 0x20CBCF, 0x20CEC1, 0x20CEC5, 0x20CFC2, 0x20D0CF, 0x20D0D2, 0x20D2C1, 0x20D3CF, 0x20D3D4, 0x20D4CF, 0x20D720, 0x20D7CF, 0x20DAC1, 0x20C4CF, 0x20C920, 0x20CBC1, 0x20CBCF, 0x20CEC1, 0x20CEC5, 0x20CFC2, 0x20D0CF, 0x20D0D2, 0x20D2C1, 0x20D3CF, 0x20D3D4, 0x20D4CF, 0x20D720, 0x20D7CF, 0x20DAC1,
0x20DCD4, 0x20DED4, 0xC1CEC9, 0xC1D4D8, 0xC5CCD8, 0xC5CEC9, 0xC5D3D4, 0xC5D420, 0xC7CF20, 0xC920D0, 0xC9C520, 0xC9C920, 0xC9D120, 0xCCC5CE, 0xCCC920, 0xCCD8CE, 0x20DCD4, 0x20DED4, 0xC1CEC9, 0xC1D4D8, 0xC5CCD8, 0xC5CEC9, 0xC5D3D4, 0xC5D420, 0xC7CF20, 0xC920D0, 0xC9C520, 0xC9C920, 0xC9D120, 0xCCC5CE, 0xCCC920, 0xCCD8CE,
0xCEC120, 0xCEC520, 0xCEC9C5, 0xCEC9D1, 0xCECF20, 0xCECFD7, 0xCF20D0, 0xCF20D3, 0xCF20D7, 0xCFC7CF, 0xCFCA20, 0xCFCCD8, 0xCFCD20, 0xCFD3D4, 0xCFD720, 0xCFD7C1, 0xCEC120, 0xCEC520, 0xCEC9C5, 0xCEC9D1, 0xCECF20, 0xCECFD7, 0xCF20D0, 0xCF20D3, 0xCF20D7, 0xCFC7CF, 0xCFCA20, 0xCFCCD8, 0xCFCD20, 0xCFD3D4, 0xCFD720, 0xCFD7C1,
0xD0CFCC, 0xD0D2C5, 0xD0D2C9, 0xD0D2CF, 0xD2C1D7, 0xD2C5C4, 0xD3D120, 0xD3D4C1, 0xD3D4C9, 0xD3D4D7, 0xD4C5CC, 0xD4CF20, 0xD4CFD2, 0xD4D820, 0xD9C820, 0xDED4CF, 0xD0CFCC, 0xD0D2C5, 0xD0D2C9, 0xD0D2CF, 0xD2C1D7, 0xD2C5C4, 0xD3D120, 0xD3D4C1, 0xD3D4C9, 0xD3D4D7, 0xD4C5CC, 0xD4CF20, 0xD4CFD2, 0xD4D820, 0xD9C820, 0xDED4CF,
}; };
private static byte[] byteMap = { private static final byte[] byteMap = {
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
(byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20, (byte) 0x20,
@ -1078,7 +1078,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
return "IBM424_rtl"; return "IBM424_rtl";
} }
private static int[] ngrams = { private static final int[] ngrams = {
0x404146, 0x404148, 0x404151, 0x404171, 0x404251, 0x404256, 0x404541, 0x404546, 0x404551, 0x404556, 0x404562, 0x404569, 0x404571, 0x405441, 0x405445, 0x405641, 0x404146, 0x404148, 0x404151, 0x404171, 0x404251, 0x404256, 0x404541, 0x404546, 0x404551, 0x404556, 0x404562, 0x404569, 0x404571, 0x405441, 0x405445, 0x405641,
0x406254, 0x406954, 0x417140, 0x454041, 0x454042, 0x454045, 0x454054, 0x454056, 0x454069, 0x454641, 0x464140, 0x465540, 0x465740, 0x466840, 0x467140, 0x514045, 0x406254, 0x406954, 0x417140, 0x454041, 0x454042, 0x454045, 0x454054, 0x454056, 0x454069, 0x454641, 0x464140, 0x465540, 0x465740, 0x466840, 0x467140, 0x514045,
0x514540, 0x514671, 0x515155, 0x515540, 0x515740, 0x516840, 0x517140, 0x544041, 0x544045, 0x544140, 0x544540, 0x554041, 0x554042, 0x554045, 0x554054, 0x554056, 0x514540, 0x514671, 0x515155, 0x515540, 0x515740, 0x516840, 0x517140, 0x544041, 0x544045, 0x544140, 0x544540, 0x554041, 0x554042, 0x554045, 0x554054, 0x554056,
@ -1098,7 +1098,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
return "IBM424_ltr"; return "IBM424_ltr";
} }
private static int[] ngrams = { private static final int[] ngrams = {
0x404146, 0x404154, 0x404551, 0x404554, 0x404556, 0x404558, 0x405158, 0x405462, 0x405469, 0x405546, 0x405551, 0x405746, 0x405751, 0x406846, 0x406851, 0x407141, 0x404146, 0x404154, 0x404551, 0x404554, 0x404556, 0x404558, 0x405158, 0x405462, 0x405469, 0x405546, 0x405551, 0x405746, 0x405751, 0x406846, 0x406851, 0x407141,
0x407146, 0x407151, 0x414045, 0x414054, 0x414055, 0x414071, 0x414540, 0x414645, 0x415440, 0x415640, 0x424045, 0x424055, 0x424071, 0x454045, 0x454051, 0x454054, 0x407146, 0x407151, 0x414045, 0x414054, 0x414055, 0x414071, 0x414540, 0x414645, 0x415440, 0x415640, 0x424045, 0x424055, 0x424071, 0x454045, 0x454051, 0x454054,
0x454055, 0x454057, 0x454068, 0x454071, 0x455440, 0x464140, 0x464540, 0x484140, 0x514140, 0x514240, 0x514540, 0x544045, 0x544055, 0x544071, 0x546240, 0x546940, 0x454055, 0x454057, 0x454068, 0x454071, 0x455440, 0x464140, 0x464540, 0x484140, 0x514140, 0x514240, 0x514540, 0x544045, 0x544055, 0x544071, 0x546240, 0x546940,
@ -1144,7 +1144,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_IBM420_ar_rtl extends CharsetRecog_IBM420_ar { static class CharsetRecog_IBM420_ar_rtl extends CharsetRecog_IBM420_ar {
private static int[] ngrams = { private static final int[] ngrams = {
0x4056B1, 0x4056BD, 0x405856, 0x409AB1, 0x40ABDC, 0x40B1B1, 0x40BBBD, 0x40CF56, 0x564056, 0x564640, 0x566340, 0x567540, 0x56B140, 0x56B149, 0x56B156, 0x56B158, 0x4056B1, 0x4056BD, 0x405856, 0x409AB1, 0x40ABDC, 0x40B1B1, 0x40BBBD, 0x40CF56, 0x564056, 0x564640, 0x566340, 0x567540, 0x56B140, 0x56B149, 0x56B156, 0x56B158,
0x56B163, 0x56B167, 0x56B169, 0x56B173, 0x56B178, 0x56B19A, 0x56B1AD, 0x56B1BB, 0x56B1CF, 0x56B1DC, 0x56BB40, 0x56BD40, 0x56BD63, 0x584056, 0x624056, 0x6240AB, 0x56B163, 0x56B167, 0x56B169, 0x56B173, 0x56B178, 0x56B19A, 0x56B1AD, 0x56B1BB, 0x56B1CF, 0x56B1DC, 0x56BB40, 0x56BD40, 0x56BD63, 0x584056, 0x624056, 0x6240AB,
0x6240B1, 0x6240BB, 0x6240CF, 0x634056, 0x734056, 0x736240, 0x754056, 0x756240, 0x784056, 0x9A4056, 0x9AB1DA, 0xABDC40, 0xB14056, 0xB16240, 0xB1DA40, 0xB1DC40, 0x6240B1, 0x6240BB, 0x6240CF, 0x634056, 0x734056, 0x736240, 0x754056, 0x756240, 0x784056, 0x9A4056, 0x9AB1DA, 0xABDC40, 0xB14056, 0xB16240, 0xB1DA40, 0xB1DC40,
@ -1165,7 +1165,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
} }
static class CharsetRecog_IBM420_ar_ltr extends CharsetRecog_IBM420_ar { static class CharsetRecog_IBM420_ar_ltr extends CharsetRecog_IBM420_ar {
private static int[] ngrams = { private static final int[] ngrams = {
0x404656, 0x4056BB, 0x4056BF, 0x406273, 0x406275, 0x4062B1, 0x4062BB, 0x4062DC, 0x406356, 0x407556, 0x4075DC, 0x40B156, 0x40BB56, 0x40BD56, 0x40BDBB, 0x40BDCF, 0x404656, 0x4056BB, 0x4056BF, 0x406273, 0x406275, 0x4062B1, 0x4062BB, 0x4062DC, 0x406356, 0x407556, 0x4075DC, 0x40B156, 0x40BB56, 0x40BD56, 0x40BDBB, 0x40BDCF,
0x40BDDC, 0x40DAB1, 0x40DCAB, 0x40DCB1, 0x49B156, 0x564056, 0x564058, 0x564062, 0x564063, 0x564073, 0x564075, 0x564078, 0x56409A, 0x5640B1, 0x5640BB, 0x5640BD, 0x40BDDC, 0x40DAB1, 0x40DCAB, 0x40DCB1, 0x49B156, 0x564056, 0x564058, 0x564062, 0x564063, 0x564073, 0x564075, 0x564078, 0x56409A, 0x5640B1, 0x5640BB, 0x5640BD,
0x5640BF, 0x5640DA, 0x5640DC, 0x565840, 0x56B156, 0x56CF40, 0x58B156, 0x63B156, 0x63BD56, 0x67B156, 0x69B156, 0x73B156, 0x78B156, 0x9AB156, 0xAB4062, 0xADB156, 0x5640BF, 0x5640DA, 0x5640DC, 0x565840, 0x56B156, 0x56CF40, 0x58B156, 0x63B156, 0x63BD56, 0x67B156, 0x69B156, 0x73B156, 0x78B156, 0x9AB156, 0xAB4062, 0xADB156,

@ -25,12 +25,14 @@ package io.legado.app.lib.icu4j;
abstract class CharsetRecognizer { abstract class CharsetRecognizer {
/** /**
* Get the IANA name of this charset. * Get the IANA name of this charset.
*
* @return the charset name. * @return the charset name.
*/ */
abstract String getName(); abstract String getName();
/** /**
* Get the ISO language code for this charset. * Get the ISO language code for this charset.
*
* @return the language code, or <code>null</code> if the language cannot be determined. * @return the language code, or <code>null</code> if the language cannot be determined.
*/ */
public String getLanguage() { public String getLanguage() {
@ -39,12 +41,12 @@ abstract class CharsetRecognizer {
/** /**
* Test the match of this charset with the input text data * Test the match of this charset with the input text data
* which is obtained via the CharsetDetector object. * which is obtained via the CharsetDetector object.
* *
* @param det The CharsetDetector, which contains the input text * @param det The CharsetDetector, which contains the input text
* to be checked for being in this charset. * to be checked for being in this charset.
* @return A CharsetMatch object containing details of match * @return A CharsetMatch object containing details of match
* with this charset, or null if there was no match. * with this charset, or null if there was no match.
*/ */
abstract CharsetMatch match(CharsetDetector det); abstract CharsetMatch match(CharsetDetector det);

@ -14,7 +14,10 @@ import androidx.core.graphics.drawable.DrawableCompat
@Suppress("unused") @Suppress("unused")
object DrawableUtils { object DrawableUtils {
fun createTransitionDrawable(@ColorInt startColor: Int, @ColorInt endColor: Int): TransitionDrawable { fun createTransitionDrawable(
@ColorInt startColor: Int,
@ColorInt endColor: Int
): TransitionDrawable {
return createTransitionDrawable(ColorDrawable(startColor), ColorDrawable(endColor)) return createTransitionDrawable(ColorDrawable(startColor), ColorDrawable(endColor))
} }
@ -27,7 +30,11 @@ object DrawableUtils {
return TransitionDrawable(drawables) return TransitionDrawable(drawables)
} }
fun setTintList(drawable: Drawable?, tint: ColorStateList, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { fun setTintList(
drawable: Drawable?,
tint: ColorStateList,
tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP
) {
drawable?.let { drawable?.let {
val wrappedDrawable = DrawableCompat.wrap(it) val wrappedDrawable = DrawableCompat.wrap(it)
wrappedDrawable.mutate() wrappedDrawable.mutate()
@ -37,7 +44,11 @@ object DrawableUtils {
} }
fun setTint(drawable: Drawable?, @ColorInt tint: Int, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { fun setTint(
drawable: Drawable?,
@ColorInt tint: Int,
tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP
) {
drawable?.let { drawable?.let {
val wrappedDrawable = DrawableCompat.wrap(it) val wrappedDrawable = DrawableCompat.wrap(it)
wrappedDrawable.mutate() wrappedDrawable.mutate()

@ -11,17 +11,31 @@ import com.google.android.material.navigation.NavigationView
@Suppress("unused") @Suppress("unused")
object NavigationViewUtils { object NavigationViewUtils {
fun setItemIconColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) { fun setItemIconColors(
navigationView: NavigationView,
@ColorInt normalColor: Int,
@ColorInt selectedColor: Int
) {
val iconSl = ColorStateList( val iconSl = ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)), arrayOf(
intArrayOf(-android.R.attr.state_checked),
intArrayOf(android.R.attr.state_checked)
),
intArrayOf(normalColor, selectedColor) intArrayOf(normalColor, selectedColor)
) )
navigationView.itemIconTintList = iconSl navigationView.itemIconTintList = iconSl
} }
fun setItemTextColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) { fun setItemTextColors(
navigationView: NavigationView,
@ColorInt normalColor: Int,
@ColorInt selectedColor: Int
) {
val textSl = ColorStateList( val textSl = ColorStateList(
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)), arrayOf(
intArrayOf(-android.R.attr.state_checked),
intArrayOf(android.R.attr.state_checked)
),
intArrayOf(normalColor, selectedColor) intArrayOf(normalColor, selectedColor)
) )
navigationView.itemTextColor = textSl navigationView.itemTextColor = textSl

@ -63,7 +63,12 @@ object Selector {
private var hasSetFocusedStrokeColor = false private var hasSetFocusedStrokeColor = false
private var hasSetCheckedStrokeColor = false private var hasSetCheckedStrokeColor = false
@IntDef(GradientDrawable.RECTANGLE, GradientDrawable.OVAL, GradientDrawable.LINE, GradientDrawable.RING) @IntDef(
GradientDrawable.RECTANGLE,
GradientDrawable.OVAL,
GradientDrawable.LINE,
GradientDrawable.RING
)
private annotation class Shape private annotation class Shape
init { init {

@ -5,28 +5,28 @@ package io.legado.app.lib.theme
*/ */
object ThemeStorePrefKeys { object ThemeStorePrefKeys {
const val CONFIG_PREFS_KEY_DEFAULT = "app_themes" const val CONFIG_PREFS_KEY_DEFAULT = "app_themes"
const val IS_CONFIGURED_KEY = "is_configured" const val IS_CONFIGURED_KEY = "is_configured"
const val IS_CONFIGURED_VERSION_KEY = "is_configured_version" const val IS_CONFIGURED_VERSION_KEY = "is_configured_version"
const val VALUES_CHANGED = "values_changed" const val VALUES_CHANGED = "values_changed"
const val KEY_PRIMARY_COLOR = "primary_color" const val KEY_PRIMARY_COLOR = "primary_color"
const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark" const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark"
const val KEY_ACCENT_COLOR = "accent_color" const val KEY_ACCENT_COLOR = "accent_color"
const val KEY_STATUS_BAR_COLOR = "status_bar_color" const val KEY_STATUS_BAR_COLOR = "status_bar_color"
const val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color" const val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color"
const val KEY_TEXT_COLOR_PRIMARY = "text_color_primary" const val KEY_TEXT_COLOR_PRIMARY = "text_color_primary"
const val KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse" const val KEY_TEXT_COLOR_PRIMARY_INVERSE = "text_color_primary_inverse"
const val KEY_TEXT_COLOR_SECONDARY = "text_color_secondary" const val KEY_TEXT_COLOR_SECONDARY = "text_color_secondary"
const val KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse" const val KEY_TEXT_COLOR_SECONDARY_INVERSE = "text_color_secondary_inverse"
const val KEY_BACKGROUND_COLOR = "backgroundColor" const val KEY_BACKGROUND_COLOR = "backgroundColor"
const val KEY_BOTTOM_BACKGROUND = "bottomBackground" const val KEY_BOTTOM_BACKGROUND = "bottomBackground"
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar" const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar" const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
const val KEY_ELEVATION = "elevation" const val KEY_ELEVATION = "elevation"
} }

@ -124,7 +124,7 @@ object Debug {
log(webBook.sourceUrl, "⇒开始访问发现页:$url") log(webBook.sourceUrl, "⇒开始访问发现页:$url")
exploreDebug(scope, webBook, url) exploreDebug(scope, webBook, url)
} }
key.startsWith("++")-> { key.startsWith("++") -> {
val url = key.substring(2) val url = key.substring(2)
val book = Book() val book = Book()
book.origin = webBook.sourceUrl book.origin = webBook.sourceUrl
@ -132,7 +132,7 @@ object Debug {
log(webBook.sourceUrl, "⇒开始访目录页:$url") log(webBook.sourceUrl, "⇒开始访目录页:$url")
tocDebug(scope, webBook, book) tocDebug(scope, webBook, book)
} }
key.startsWith("--")-> { key.startsWith("--") -> {
val url = key.substring(2) val url = key.substring(2)
val book = Book() val book = Book()
book.origin = webBook.sourceUrl book.origin = webBook.sourceUrl

@ -30,14 +30,14 @@ class AnalyzeByJSonPath(json: Any) {
fun getString(rule: String): String? { fun getString(rule: String): String? {
if (rule.isEmpty()) return null if (rule.isEmpty()) return null
var result: String var result: String
val ruleAnalyzes = RuleAnalyzer(rule,true) //设置平衡组为代码平衡 val ruleAnalyzes = RuleAnalyzer(rule, true) //设置平衡组为代码平衡
val rules = ruleAnalyzes.splitRule("&&","||") val rules = ruleAnalyzes.splitRule("&&", "||")
if (rules.size == 1) { if (rules.size == 1) {
ruleAnalyzes.reSetPos() //将pos重置为0,复用解析器 ruleAnalyzes.reSetPos() //将pos重置为0,复用解析器
result = ruleAnalyzes.innerRule("{$."){ getString(it) } //替换所有{$.rule...} result = ruleAnalyzes.innerRule("{$.") { getString(it) } //替换所有{$.rule...}
if (result.isEmpty()) { //st为空,表明无成功替换的内嵌规则 if (result.isEmpty()) { //st为空,表明无成功替换的内嵌规则
@ -45,7 +45,7 @@ class AnalyzeByJSonPath(json: Any) {
val ob = ctx.read<Any>(rule) val ob = ctx.read<Any>(rule)
result =(if (ob is List<*>) { result = (if (ob is List<*>) {
val builder = StringBuilder() val builder = StringBuilder()
for (o in ob) { for (o in ob) {
@ -83,14 +83,14 @@ class AnalyzeByJSonPath(json: Any) {
internal fun getStringList(rule: String): List<String> { internal fun getStringList(rule: String): List<String> {
val result = ArrayList<String>() val result = ArrayList<String>()
if (rule.isEmpty()) return result if (rule.isEmpty()) return result
val ruleAnalyzes = RuleAnalyzer(rule,true) //设置平衡组为代码平衡 val ruleAnalyzes = RuleAnalyzer(rule, true) //设置平衡组为代码平衡
val rules = ruleAnalyzes.splitRule("&&","||","%%") val rules = ruleAnalyzes.splitRule("&&", "||", "%%")
if (rules.size == 1) { if (rules.size == 1) {
ruleAnalyzes.reSetPos() //将pos重置为0,复用解析器 ruleAnalyzes.reSetPos() //将pos重置为0,复用解析器
val st = ruleAnalyzes.innerRule("{$."){ getString(it) } //替换所有{$.rule...} val st = ruleAnalyzes.innerRule("{$.") { getString(it) } //替换所有{$.rule...}
if (st.isEmpty()) { //st为空,表明无成功替换的内嵌规则 if (st.isEmpty()) { //st为空,表明无成功替换的内嵌规则
@ -107,7 +107,7 @@ class AnalyzeByJSonPath(json: Any) {
} catch (ignored: Exception) { } catch (ignored: Exception) {
} }
}else result.add(st) } else result.add(st)
return result return result
@ -148,8 +148,8 @@ class AnalyzeByJSonPath(json: Any) {
internal fun getList(rule: String): ArrayList<Any>? { internal fun getList(rule: String): ArrayList<Any>? {
val result = ArrayList<Any>() val result = ArrayList<Any>()
if (rule.isEmpty()) return result if (rule.isEmpty()) return result
val ruleAnalyzes = RuleAnalyzer(rule,true) //设置平衡组为代码平衡 val ruleAnalyzes = RuleAnalyzer(rule, true) //设置平衡组为代码平衡
val rules = ruleAnalyzes.splitRule("&&","||","%%") val rules = ruleAnalyzes.splitRule("&&", "||", "%%")
if (rules.size == 1) { if (rules.size == 1) {
ctx.let { ctx.let {
try { try {

@ -42,13 +42,14 @@ class AnalyzeByJSoup(doc: Any) {
* 合并内容列表,得到内容 * 合并内容列表,得到内容
*/ */
internal fun getString(ruleStr: String) = internal fun getString(ruleStr: String) =
if(ruleStr.isEmpty()) null if (ruleStr.isEmpty()) null
else getStringList(ruleStr).takeIf { it.isNotEmpty() }?.joinToString("\n") else getStringList(ruleStr).takeIf { it.isNotEmpty() }?.joinToString("\n")
/** /**
* 获取一个字符串 * 获取一个字符串
*/ */
internal fun getString0(ruleStr: String) = getStringList(ruleStr).let{ if ( it.isEmpty() ) "" else it[0] } internal fun getString0(ruleStr: String) =
getStringList(ruleStr).let { if (it.isEmpty()) "" else it[0] }
/** /**
* 获取所有内容列表 * 获取所有内容列表
@ -69,7 +70,7 @@ class AnalyzeByJSoup(doc: Any) {
} else { } else {
val ruleAnalyzes = RuleAnalyzer(sourceRule.elementsRule) val ruleAnalyzes = RuleAnalyzer(sourceRule.elementsRule)
val ruleStrS = ruleAnalyzes.splitRule("&&","||" ,"%%") val ruleStrS = ruleAnalyzes.splitRule("&&", "||", "%%")
val results = ArrayList<List<String>>() val results = ArrayList<List<String>>()
for (ruleStrX in ruleStrS) { for (ruleStrX in ruleStrS) {
@ -123,7 +124,7 @@ class AnalyzeByJSoup(doc: Any) {
val sourceRule = SourceRule(rule) val sourceRule = SourceRule(rule)
val ruleAnalyzes = RuleAnalyzer(sourceRule.elementsRule) val ruleAnalyzes = RuleAnalyzer(sourceRule.elementsRule)
val ruleStrS = ruleAnalyzes.splitRule("&&","||","%%") val ruleStrS = ruleAnalyzes.splitRule("&&", "||", "%%")
val elementsList = ArrayList<Elements>() val elementsList = ArrayList<Elements>()
if (sourceRule.isCss) { if (sourceRule.isCss) {
@ -155,7 +156,7 @@ class AnalyzeByJSoup(doc: Any) {
el.addAll(es) el.addAll(es)
} }
el el
}else ElementsSingle().getElementsSingle(temp,ruleStr) } else ElementsSingle().getElementsSingle(temp, ruleStr)
elementsList.add(el) elementsList.add(el)
if (el.size > 0 && ruleAnalyzes.elementsType == "||") { if (el.size > 0 && ruleAnalyzes.elementsType == "||") {
@ -275,10 +276,12 @@ class AnalyzeByJSoup(doc: Any) {
* 特殊用法 tag.div[-1:0] 可在任意地方让列表反向 * 特殊用法 tag.div[-1:0] 可在任意地方让列表反向
* *
* */ * */
data class ElementsSingle(var split:Char = '.', data class ElementsSingle(
var beforeRule:String = "", var split: Char = '.',
val indexDefault:MutableList<Int> = mutableListOf(), var beforeRule: String = "",
val indexs:MutableList<Any> = mutableListOf()){ val indexDefault: MutableList<Int> = mutableListOf(),
val indexs: MutableList<Any> = mutableListOf()
) {
/** /**
* 获取Elements按照一个规则 * 获取Elements按照一个规则
*/ */
@ -289,43 +292,44 @@ class AnalyzeByJSoup(doc: Any) {
/** /**
* 获取所有元素 * 获取所有元素
* */ * */
var elements = if (beforeRule.isEmpty()) temp.children() //允许索引直接作为根元素,此时前置规则为空,效果与children相同 var elements =
else { if (beforeRule.isEmpty()) temp.children() //允许索引直接作为根元素,此时前置规则为空,效果与children相同
val rules = beforeRule.split(".") else {
when (rules[0]) { val rules = beforeRule.split(".")
"children" -> temp.children() //允许索引直接作为根元素,此时前置规则为空,效果与children相同 when (rules[0]) {
"class" -> temp.getElementsByClass(rules[1]) "children" -> temp.children() //允许索引直接作为根元素,此时前置规则为空,效果与children相同
"tag" -> temp.getElementsByTag(rules[1]) "class" -> temp.getElementsByClass(rules[1])
"id" -> Collector.collect(Evaluator.Id(rules[1]), temp) "tag" -> temp.getElementsByTag(rules[1])
"text" -> temp.getElementsContainingOwnText(rules[1]) "id" -> Collector.collect(Evaluator.Id(rules[1]), temp)
else -> temp.select(beforeRule) "text" -> temp.getElementsContainingOwnText(rules[1])
else -> temp.select(beforeRule)
}
} }
}
val len = elements.size val len = elements.size
val lastIndexs = (indexDefault.size - 1).takeIf { it !=-1 } ?: indexs.size -1 val lastIndexs = (indexDefault.size - 1).takeIf { it != -1 } ?: indexs.size - 1
val indexSet = mutableSetOf<Int>() val indexSet = mutableSetOf<Int>()
/** /**
* 获取无重且不越界的索引集合 * 获取无重且不越界的索引集合
* */ * */
if(indexs.isEmpty())for (ix in lastIndexs downTo 0 ){ //indexs为空,表明是非[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序 if (indexs.isEmpty()) for (ix in lastIndexs downTo 0) { //indexs为空,表明是非[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序
val it = indexDefault[ix] val it = indexDefault[ix]
if(it in 0 until len) indexSet.add(it) //将正数不越界的索引添加到集合 if (it in 0 until len) indexSet.add(it) //将正数不越界的索引添加到集合
else if(it < 0 && len >= -it) indexSet.add(it + len) //将负数不越界的索引添加到集合 else if (it < 0 && len >= -it) indexSet.add(it + len) //将负数不越界的索引添加到集合
}else for (ix in lastIndexs downTo 0 ){ //indexs不空,表明是[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序 } else for (ix in lastIndexs downTo 0) { //indexs不空,表明是[]式索引,集合是逆向遍历插入的,所以这里也逆向遍历,好还原顺序
if(indexs[ix] is Triple<*, *, *>){ //区间 if (indexs[ix] is Triple<*, *, *>) { //区间
val (startx, endx, stepx) = indexs[ix] as Triple<Int?, Int?, Int> //还原储存时的类型 val (startx, endx, stepx) = indexs[ix] as Triple<Int?, Int?, Int> //还原储存时的类型
val start = if (startx == null) 0 //左端省略表示0 val start = if (startx == null) 0 //左端省略表示0
else if (startx >= 0) if (startx < len) startx else len - 1 //右端越界,设置为最大索引 else if (startx >= 0) if (startx < len) startx else len - 1 //右端越界,设置为最大索引
else if (-startx <= len) len + startx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 else if (-startx <= len) len + startx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引
val end = if (endx == null) len - 1 //右端省略表示 len - 1 val end = if (endx == null) len - 1 //右端省略表示 len - 1
else if (endx >= 0) if (endx < len) endx else len - 1 //右端越界,设置为最大索引 else if (endx >= 0) if (endx < len) endx else len - 1 //右端越界,设置为最大索引
else if (-endx <= len) len + endx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引 else if (-endx <= len) len + endx /* 将负索引转正 */ else 0 //左端越界,设置为最小索引
@ -336,17 +340,18 @@ class AnalyzeByJSoup(doc: Any) {
} }
val step = if (stepx > 0) stepx else if (-stepx < len) stepx + len else 1 //最小正数间隔为1 val step =
if (stepx > 0) stepx else if (-stepx < len) stepx + len else 1 //最小正数间隔为1
//将区间展开到集合中,允许列表反向。 //将区间展开到集合中,允许列表反向。
indexSet.addAll(if (end > start) start..end step step else start downTo end step step) indexSet.addAll(if (end > start) start..end step step else start downTo end step step)
}else{//单个索引 } else {//单个索引
val it = indexs[ix] as Int //还原储存时的类型 val it = indexs[ix] as Int //还原储存时的类型
if(it in 0 until len) indexSet.add(it) //将正数不越界的索引添加到集合 if (it in 0 until len) indexSet.add(it) //将正数不越界的索引添加到集合
else if(it < 0 && len >= -it) indexSet.add(it + len) //将负数不越界的索引添加到集合 else if (it < 0 && len >= -it) indexSet.add(it + len) //将负数不越界的索引添加到集合
} }
@ -355,13 +360,13 @@ class AnalyzeByJSoup(doc: Any) {
/** /**
* 根据索引集合筛选元素 * 根据索引集合筛选元素
* */ * */
if(split == '!'){ //排除 if (split == '!') { //排除
for (pcInt in indexSet) elements[pcInt] = null for (pcInt in indexSet) elements[pcInt] = null
elements.removeAll(listOf(null)) //测试过,这样就行 elements.removeAll(listOf(null)) //测试过,这样就行
}else if(split == '.'){ //选择 } else if (split == '.') { //选择
val es = Elements() val es = Elements()
@ -375,9 +380,9 @@ class AnalyzeByJSoup(doc: Any) {
} }
private fun findIndexSet( rule:String ){ private fun findIndexSet(rule: String) {
val rus = rule.trim{ it <= ' '} val rus = rule.trim { it <= ' ' }
var len = rus.length var len = rus.length
var curInt: Int? //当前数字 var curInt: Int? //当前数字
@ -387,7 +392,7 @@ class AnalyzeByJSoup(doc: Any) {
val head = rus.last() == ']' //是否为常规索引写法 val head = rus.last() == ']' //是否为常规索引写法
if(head){ //常规索引写法[index...] if (head) { //常规索引写法[index...]
len-- //跳过尾部']' len-- //跳过尾部']'
@ -400,7 +405,8 @@ class AnalyzeByJSoup(doc: Any) {
else if (rl == '-') curMinus = true else if (rl == '-') curMinus = true
else { else {
curInt = if (l.isEmpty()) null else if (curMinus) -l.toInt() else l.toInt() //当前数字 curInt =
if (l.isEmpty()) null else if (curMinus) -l.toInt() else l.toInt() //当前数字
when (rl) { when (rl) {
@ -409,32 +415,39 @@ class AnalyzeByJSoup(doc: Any) {
else -> { else -> {
//为保证查找顺序,区间和单个索引都添加到同一集合 //为保证查找顺序,区间和单个索引都添加到同一集合
if(curList.isEmpty()) { if (curList.isEmpty()) {
if(curInt == null) break //是jsoup选择器而非索引列表,跳出 if (curInt == null) break //是jsoup选择器而非索引列表,跳出
indexs.add(curInt) indexs.add(curInt)
} } else {
else{
//列表最后压入的是区间右端,若列表有两位则最先压入的是间隔 //列表最后压入的是区间右端,若列表有两位则最先压入的是间隔
indexs.add( Triple(curInt, curList.last(), if(curList.size == 2) curList.first() else 1) ) indexs.add(
Triple(
curInt,
curList.last(),
if (curList.size == 2) curList.first() else 1
)
)
curList.clear() //重置临时列表,避免影响到下个区间的处理 curList.clear() //重置临时列表,避免影响到下个区间的处理
} }
if(rl == '!'){ if (rl == '!') {
split='!' split = '!'
do{ rl = rus[--len] } while (len > 0 && rl == ' ')//跳过所有空格 do {
rl = rus[--len]
} while (len > 0 && rl == ' ')//跳过所有空格
} }
if(rl == '[') { if (rl == '[') {
beforeRule = rus.substring(0, len) //遇到索引边界,返回结果 beforeRule = rus.substring(0, len) //遇到索引边界,返回结果
return return
} }
if(rl != ',') break //非索引结构,跳出 if (rl != ',') break //非索引结构,跳出
} }
} }
@ -452,17 +465,17 @@ class AnalyzeByJSoup(doc: Any) {
else if (rl == '-') curMinus = true else if (rl == '-') curMinus = true
else { else {
if(rl == '!' || rl == '.' || rl == ':') { //分隔符或起始符 if (rl == '!' || rl == '.' || rl == ':') { //分隔符或起始符
indexDefault.add(if (curMinus) -l.toInt() else l.toInt()) // 当前数字追加到列表 indexDefault.add(if (curMinus) -l.toInt() else l.toInt()) // 当前数字追加到列表
if (rl != ':'){ //rl == '!' || rl == '.' if (rl != ':') { //rl == '!' || rl == '.'
split = rl split = rl
beforeRule = rus.substring(0, len) beforeRule = rus.substring(0, len)
return return
} }
}else break //非索引结构,跳出循环 } else break //非索引结构,跳出循环
l = "" //清空 l = "" //清空
curMinus = false //重置 curMinus = false //重置

@ -45,11 +45,11 @@ class AnalyzeByXPath(doc: Any) {
internal fun getElements(xPath: String): List<JXNode>? { internal fun getElements(xPath: String): List<JXNode>? {
if(xPath.isEmpty()) return null if (xPath.isEmpty()) return null
val jxNodes = ArrayList<JXNode>() val jxNodes = ArrayList<JXNode>()
val ruleAnalyzes = RuleAnalyzer(xPath) val ruleAnalyzes = RuleAnalyzer(xPath)
val rules = ruleAnalyzes.splitRule("&&","||","%%") val rules = ruleAnalyzes.splitRule("&&", "||", "%%")
if (rules.size == 1) { if (rules.size == 1) {
return getResult(rules[0]) return getResult(rules[0])
@ -87,7 +87,7 @@ class AnalyzeByXPath(doc: Any) {
val result = ArrayList<String>() val result = ArrayList<String>()
val ruleAnalyzes = RuleAnalyzer(xPath) val ruleAnalyzes = RuleAnalyzer(xPath)
val rules = ruleAnalyzes.splitRule("&&","||","%%") val rules = ruleAnalyzes.splitRule("&&", "||", "%%")
if (rules.size == 1) { if (rules.size == 1) {
getResult(xPath)?.map { getResult(xPath)?.map {
@ -126,7 +126,7 @@ class AnalyzeByXPath(doc: Any) {
fun getString(rule: String): String? { fun getString(rule: String): String? {
val ruleAnalyzes = RuleAnalyzer(rule) val ruleAnalyzes = RuleAnalyzer(rule)
val rules = ruleAnalyzes.splitRule("&&","||") val rules = ruleAnalyzes.splitRule("&&", "||")
if (rules.size == 1) { if (rules.size == 1) {
getResult(rule)?.let { getResult(rule)?.let {
return TextUtils.join("\n", it) return TextUtils.join("\n", it)

@ -19,7 +19,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) {
var innerType = true //是否为内嵌{{}} var innerType = true //是否为内嵌{{}}
fun trim() { // 修剪当前规则之前的"@"或者空白符 fun trim() { // 修剪当前规则之前的"@"或者空白符
if(queue[pos] == '@' || queue[pos] < '!') { //在while里重复设置start和startX会拖慢执行速度,所以先来个判断是否存在需要修剪的字段,最后再一次性设置start和startX if (queue[pos] == '@' || queue[pos] < '!') { //在while里重复设置start和startX会拖慢执行速度,所以先来个判断是否存在需要修剪的字段,最后再一次性设置start和startX
pos++ pos++
while (queue[pos] == '@' || queue[pos] < '!') pos++ while (queue[pos] == '@' || queue[pos] < '!') pos++
start = pos //开始点推移 start = pos //开始点推移
@ -258,7 +258,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) {
val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符 val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符
if (!chompBalanced(queue[pos], next)) throw Error( if (!chompBalanced(queue[pos], next)) throw Error(
queue.substring(0,start) + "后未平衡" queue.substring(0, start) + "后未平衡"
) //拉出一个筛选器,不平衡则报错 ) //拉出一个筛选器,不平衡则报错
} while (end > pos) } while (end > pos)
@ -315,7 +315,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) {
val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符 val next = if (queue[pos] == '[') ']' else ')' //平衡组末尾字符
if (!chompBalanced(queue[pos], next)) throw Error( if (!chompBalanced(queue[pos], next)) throw Error(
queue.substring(0,start) + "后未平衡" queue.substring(0, start) + "后未平衡"
) //拉出一个筛选器,不平衡则报错 ) //拉出一个筛选器,不平衡则报错
} while (end > pos) } while (end > pos)
@ -338,10 +338,10 @@ class RuleAnalyzer(data: String, code: Boolean = false) {
* *
* */ * */
fun innerRule( fun innerRule(
inner: String, inner: String,
startStep: Int = 1, startStep: Int = 1,
endStep: Int = 1, endStep: Int = 1,
fr: (String) -> String? fr: (String) -> String?
): String { ): String {
val st = StringBuilder() val st = StringBuilder()
@ -358,7 +358,7 @@ class RuleAnalyzer(data: String, code: Boolean = false) {
pos += inner.length //拉出字段不平衡,inner只是个普通字串,跳到此inner后继续匹配 pos += inner.length //拉出字段不平衡,inner只是个普通字串,跳到此inner后继续匹配
} }
return if(startX == 0) "" else st.apply { return if (startX == 0) "" else st.apply {
append(queue.substring(startX)) append(queue.substring(startX))
}.toString() }.toString()
} }

@ -26,22 +26,30 @@ object LocalBook {
} }
fun getChapterList(book: Book): ArrayList<BookChapter> { fun getChapterList(book: Book): ArrayList<BookChapter> {
return if (book.isEpub()) { return when {
EpubFile.getChapterList(book) book.isEpub() -> {
}else if(book.isUmd()){ EpubFile.getChapterList(book)
UmdFile.getChapterList(book) }
} else { book.isUmd() -> {
AnalyzeTxtFile().analyze(book) UmdFile.getChapterList(book)
}
else -> {
AnalyzeTxtFile().analyze(book)
}
} }
} }
fun getContext(book: Book, chapter: BookChapter): String? { fun getContext(book: Book, chapter: BookChapter): String? {
return if (book.isEpub()) { return when {
EpubFile.getContent(book, chapter) book.isEpub() -> {
}else if (book.isUmd()){ EpubFile.getContent(book, chapter)
UmdFile.getContent(book, chapter) }
} else { book.isUmd() -> {
AnalyzeTxtFile.getContent(book, chapter) UmdFile.getContent(book, chapter)
}
else -> {
AnalyzeTxtFile.getContent(book, chapter)
}
} }
} }
@ -65,7 +73,7 @@ object LocalBook {
path = uri.path!! path = uri.path!!
File(path).name File(path).name
}) })
val tempFileName=fileName.replace(Regex("\\.txt$"), "") val tempFileName = fileName.replace(Regex("\\.txt$"), "")
val name: String val name: String
val author: String val author: String
@ -97,7 +105,7 @@ object LocalBook {
AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})", AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})",
//将文件名注入到脚步的src变量中 //将文件名注入到脚步的src变量中
SimpleBindings().also{ it["src"] = tempFileName } SimpleBindings().also { it["src"] = tempFileName }
).toString() ).toString()
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr) ?: HashMap() val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr) ?: HashMap()
name = bookMess["name"] ?: tempFileName name = bookMess["name"] ?: tempFileName
@ -132,7 +140,7 @@ object LocalBook {
fun deleteBook(book: Book, deleteOriginal: Boolean) { fun deleteBook(book: Book, deleteOriginal: Boolean) {
kotlin.runCatching { kotlin.runCatching {
if (book.isLocalTxt()||book.isUmd()) { if (book.isLocalTxt() || book.isUmd()) {
val bookFile = FileUtils.getFile(cacheFolder, book.originName) val bookFile = FileUtils.getFile(cacheFolder, book.originName)
bookFile.delete() bookFile.delete()
} }

@ -56,7 +56,6 @@ class UmdFile(var book: Book) {
} }
private var umdBook: UmdBook? = null private var umdBook: UmdBook? = null
get() { get() {
if (field != null) { if (field != null) {
@ -67,7 +66,6 @@ class UmdFile(var book: Book) {
} }
init { init {
try { try {
umdBook?.let { umdBook?.let {
@ -79,7 +77,7 @@ class UmdFile(var book: Book) {
) )
} }
if (!File(book.coverUrl!!).exists()) { if (!File(book.coverUrl!!).exists()) {
FileUtils.writeBytes(book.coverUrl!!,it.cover.coverData) FileUtils.writeBytes(book.coverUrl!!, it.cover.coverData)
} }
} }
@ -87,8 +85,9 @@ class UmdFile(var book: Book) {
e.printStackTrace() e.printStackTrace()
} }
} }
private fun readUmd(): UmdBook? { private fun readUmd(): UmdBook? {
val input= if (book.bookUrl.isContentScheme()) { val input = if (book.bookUrl.isContentScheme()) {
val uri = Uri.parse(book.bookUrl) val uri = Uri.parse(book.bookUrl)
appCtx.contentResolver.openInputStream(uri) appCtx.contentResolver.openInputStream(uri)
} else { } else {
@ -98,18 +97,19 @@ class UmdFile(var book: Book) {
} }
private fun upBookInfo() { private fun upBookInfo() {
if(umdBook==null){ if (umdBook == null) {
uFile = null uFile = null
book.intro = "书籍导入异常" book.intro = "书籍导入异常"
}else{ } else {
val hd= umdBook!!.header val hd = umdBook!!.header
book.name=hd.title; book.name = hd.title
book.author=hd.author; book.author = hd.author
book.kind=hd.bookType; book.kind = hd.bookType
} }
} }
private fun getContent(chapter: BookChapter): String? { private fun getContent(chapter: BookChapter): String? {
return umdBook?.chapters?.getContentString(chapter.index) return umdBook?.chapters?.getContentString(chapter.index)
} }
private fun getChapterList(): ArrayList<BookChapter> { private fun getChapterList(): ArrayList<BookChapter> {
@ -117,11 +117,11 @@ class UmdFile(var book: Book) {
umdBook?.chapters?.titles?.forEachIndexed { index, _ -> umdBook?.chapters?.titles?.forEachIndexed { index, _ ->
val title = umdBook!!.chapters.getTitle(index) val title = umdBook!!.chapters.getTitle(index)
val chapter = BookChapter() val chapter = BookChapter()
chapter.title=title; chapter.title = title
chapter.index = index chapter.index = index
chapter.bookUrl = book.bookUrl chapter.bookUrl = book.bookUrl
chapter.url = index.toString(); chapter.url = index.toString()
Log.d("UMD",chapter.url) Log.d("UMD", chapter.url)
chapterList.add(chapter) chapterList.add(chapter)
} }
book.latestChapterTitle = chapterList.lastOrNull()?.title book.latestChapterTitle = chapterList.lastOrNull()?.title

@ -86,8 +86,8 @@ class SearchBookModel(private val scope: CoroutineScope, private val callBack: C
} else { } else {
searchIndex++ searchIndex++
} }
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size, if (searchIndex >= bookSourceList.lastIndex
threadCount) + min(bookSourceList.size, threadCount)
) { ) {
callBack.onSearchFinish() callBack.onSearchFinish()
} }

@ -17,6 +17,7 @@ import io.legado.app.service.help.CheckSource
import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.book.source.manage.BookSourceActivity
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.min import kotlin.math.min
@ -129,14 +130,14 @@ class CheckSourceService : BaseService() {
throw Exception("正文内容为空") throw Exception("正文内容为空")
} }
}.timeout(180000L) }.timeout(180000L)
.onError { .onError(IO) {
source.addGroup("失效") source.addGroup("失效")
source.bookSourceComment = """ source.bookSourceComment = """
"error:${it.localizedMessage} "error:${it.localizedMessage}
${source.bookSourceComment}" ${source.bookSourceComment}"
""".trimIndent() """.trimIndent()
appDb.bookSourceDao.update(source) appDb.bookSourceDao.update(source)
}.onSuccess { }.onSuccess(IO) {
source.removeGroup("失效") source.removeGroup("失效")
source.bookSourceComment = source.bookSourceComment source.bookSourceComment = source.bookSourceComment
?.split("\n") ?.split("\n")

@ -21,9 +21,9 @@ import java.net.SocketTimeoutException
import java.util.* import java.util.*
class HttpReadAloudService : BaseReadAloudService(), class HttpReadAloudService : BaseReadAloudService(),
MediaPlayer.OnPreparedListener, MediaPlayer.OnPreparedListener,
MediaPlayer.OnErrorListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener { MediaPlayer.OnCompletionListener {
private val player by lazy { MediaPlayer() } private val player by lazy { MediaPlayer() }
private lateinit var ttsFolder: String private lateinit var ttsFolder: String
@ -53,7 +53,8 @@ class HttpReadAloudService : BaseReadAloudService(),
override fun play() { override fun play() {
if (contentList.isEmpty()) return if (contentList.isEmpty()) return
ReadAloud.httpTTS?.let { ReadAloud.httpTTS?.let {
val fileName = md5SpeakFileName(it.url, AppConfig.ttsSpeechRate.toString(), contentList[nowSpeak]) val fileName =
md5SpeakFileName(it.url, AppConfig.ttsSpeechRate.toString(), contentList[nowSpeak])
if (nowSpeak == 0) { if (nowSpeak == 0) {
downloadAudio() downloadAudio()
} else { } else {
@ -91,9 +92,9 @@ class HttpReadAloudService : BaseReadAloudService(),
try { try {
createSpeakCacheFile(fileName) createSpeakCacheFile(fileName)
AnalyzeUrl( AnalyzeUrl(
it.url, it.url,
speakText = item, speakText = item,
speakSpeed = AppConfig.ttsSpeechRate speakSpeed = AppConfig.ttsSpeechRate
).getByteArray().let { bytes -> ).getByteArray().let { bytes ->
ensureActive() ensureActive()
@ -153,23 +154,23 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
private fun hasSpeakFile(name: String) = private fun hasSpeakFile(name: String) =
FileUtils.exist("${speakFilePath()}$name.mp3") FileUtils.exist("${speakFilePath()}$name.mp3")
private fun hasSpeakCacheFile(name: String) = private fun hasSpeakCacheFile(name: String) =
FileUtils.exist("${speakFilePath()}$name.mp3.cache") FileUtils.exist("${speakFilePath()}$name.mp3.cache")
private fun createSpeakCacheFile(name: String): File = private fun createSpeakCacheFile(name: String): File =
FileUtils.createFileWithReplace("${speakFilePath()}$name.mp3.cache") FileUtils.createFileWithReplace("${speakFilePath()}$name.mp3.cache")
private fun removeSpeakCacheFile(name: String) { private fun removeSpeakCacheFile(name: String) {
FileUtils.delete("${speakFilePath()}$name.mp3.cache") FileUtils.delete("${speakFilePath()}$name.mp3.cache")
} }
private fun getSpeakFileAsMd5(name: String): File = private fun getSpeakFileAsMd5(name: String): File =
FileUtils.getFile(File(speakFilePath()), "$name.mp3") FileUtils.getFile(File(speakFilePath()), "$name.mp3")
private fun getSpeakFileAsMd5IfNotExist(name: String): File = private fun getSpeakFileAsMd5IfNotExist(name: String): File =
FileUtils.createFileIfNotExist("${speakFilePath()}$name.mp3") FileUtils.createFileIfNotExist("${speakFilePath()}$name.mp3")
private fun removeCacheFile() { private fun removeCacheFile() {
FileUtils.listDirsAndFiles(speakFilePath())?.forEach { FileUtils.listDirsAndFiles(speakFilePath())?.forEach {
@ -178,7 +179,7 @@ class HttpReadAloudService : BaseReadAloudService(),
} }
if (Regex(""".+\.mp3$""").matches(it.name)) { //mp3缓存文件 if (Regex(""".+\.mp3$""").matches(it.name)) { //mp3缓存文件
val reg = val reg =
"""^${MD5Utils.md5Encode16(textChapter!!.title)}_[a-z0-9]{16}\.mp3$""".toRegex() """^${MD5Utils.md5Encode16(textChapter!!.title)}_[a-z0-9]{16}\.mp3$""".toRegex()
if (!reg.matches(it.name)) { if (!reg.matches(it.name)) {
FileUtils.deleteFile(it.absolutePath) FileUtils.deleteFile(it.absolutePath)
} }

@ -233,7 +233,11 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
} }
private fun setAssets(doc: DocumentFile, book: Book, epubBook: EpubBook): String { private fun setAssets(doc: DocumentFile, book: Book, epubBook: EpubBook): String {
if(!(AppConfig.isGooglePlay|| appCtx.packageName.contains("debug",true))) return setAssets(book, epubBook) if (!(AppConfig.isGooglePlay || appCtx.packageName.contains(
"debug",
true
))
) return setAssets(book, epubBook)
var contentModel = "" var contentModel = ""
DocumentUtils.getDirDocument(doc, "Asset").let { customPath -> DocumentUtils.getDirDocument(doc, "Asset").let { customPath ->

@ -12,7 +12,8 @@ import io.legado.app.lib.theme.accentColor
import io.legado.app.ui.widget.text.StrokeTextView import io.legado.app.ui.widget.text.StrokeTextView
class TextFontWeightConverter(context: Context, attrs: AttributeSet?) : StrokeTextView(context, attrs) { class TextFontWeightConverter(context: Context, attrs: AttributeSet?) :
StrokeTextView(context, attrs) {
private val spannableString = SpannableString("中/粗/细") private val spannableString = SpannableString("中/粗/细")
private var enabledSpan: ForegroundColorSpan = ForegroundColorSpan(context.accentColor) private var enabledSpan: ForegroundColorSpan = ForegroundColorSpan(context.accentColor)

@ -23,20 +23,26 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
// 贝塞尔曲线起始点 // 贝塞尔曲线起始点
private val mBezierStart1 = PointF() private val mBezierStart1 = PointF()
// 贝塞尔曲线控制点 // 贝塞尔曲线控制点
private val mBezierControl1 = PointF() private val mBezierControl1 = PointF()
// 贝塞尔曲线顶点 // 贝塞尔曲线顶点
private val mBezierVertex1 = PointF() private val mBezierVertex1 = PointF()
// 贝塞尔曲线结束点 // 贝塞尔曲线结束点
private var mBezierEnd1 = PointF() private var mBezierEnd1 = PointF()
// 另一条贝塞尔曲线 // 另一条贝塞尔曲线
// 贝塞尔曲线起始点 // 贝塞尔曲线起始点
private val mBezierStart2 = PointF() private val mBezierStart2 = PointF()
// 贝塞尔曲线控制点 // 贝塞尔曲线控制点
private val mBezierControl2 = PointF() private val mBezierControl2 = PointF()
// 贝塞尔曲线顶点 // 贝塞尔曲线顶点
private val mBezierVertex2 = PointF() private val mBezierVertex2 = PointF()
// 贝塞尔曲线结束点 // 贝塞尔曲线结束点
private var mBezierEnd2 = PointF() private var mBezierEnd2 = PointF()
@ -60,10 +66,13 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
// 是否属于右上左下 // 是否属于右上左下
private var mIsRtOrLb = false private var mIsRtOrLb = false
private var mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat() private var mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat()
// 背面颜色组 // 背面颜色组
private var mBackShadowColors: IntArray private var mBackShadowColors: IntArray
// 前面颜色组 // 前面颜色组
private var mFrontShadowColors: IntArray private var mFrontShadowColors: IntArray
// 有阴影的GradientDrawable // 有阴影的GradientDrawable
private var mBackShadowDrawableLR: GradientDrawable private var mBackShadowDrawableLR: GradientDrawable
private var mBackShadowDrawableRL: GradientDrawable private var mBackShadowDrawableRL: GradientDrawable

@ -43,22 +43,22 @@ public class CurlMesh {
// Let's avoid using 'new' as much as possible. Meaning we introduce arrays // Let's avoid using 'new' as much as possible. Meaning we introduce arrays
// once here and reuse them on runtime. Doesn't really have very much effect // once here and reuse them on runtime. Doesn't really have very much effect
// but avoids some garbage collections from happening. // but avoids some garbage collections from happening.
private Array<ShadowVertex> mArrDropShadowVertices; private final Array<ShadowVertex> mArrDropShadowVertices;
private Array<Vertex> mArrIntersections; private final Array<Vertex> mArrIntersections;
private Array<Vertex> mArrOutputVertices; private final Array<Vertex> mArrOutputVertices;
private Array<Vertex> mArrRotatedVertices; private final Array<Vertex> mArrRotatedVertices;
private Array<Double> mArrScanLines; private final Array<Double> mArrScanLines;
private Array<ShadowVertex> mArrSelfShadowVertices; private final Array<ShadowVertex> mArrSelfShadowVertices;
private Array<ShadowVertex> mArrTempShadowVertices; private final Array<ShadowVertex> mArrTempShadowVertices;
private Array<Vertex> mArrTempVertices; private final Array<Vertex> mArrTempVertices;
// Buffers for feeding rasterizer. // Buffers for feeding rasterizer.
private FloatBuffer mBufColors; private final FloatBuffer mBufColors;
private FloatBuffer mBufCurlPositionLines; private FloatBuffer mBufCurlPositionLines;
private FloatBuffer mBufShadowColors; private final FloatBuffer mBufShadowColors;
private FloatBuffer mBufShadowVertices; private final FloatBuffer mBufShadowVertices;
private FloatBuffer mBufTexCoords; private final FloatBuffer mBufTexCoords;
private FloatBuffer mBufVertices; private final FloatBuffer mBufVertices;
private int mCurlPositionLinesCount; private int mCurlPositionLinesCount;
private int mDropShadowCount; private int mDropShadowCount;
@ -66,7 +66,7 @@ public class CurlMesh {
// Boolean for 'flipping' texture sideways. // Boolean for 'flipping' texture sideways.
private boolean mFlipTexture = false; private boolean mFlipTexture = false;
// Maximum number of split lines used for creating a curl. // Maximum number of split lines used for creating a curl.
private int mMaxCurlSplits; private final int mMaxCurlSplits;
// Bounding rectangle for this mesh. mRectagle[0] = top-left corner, // Bounding rectangle for this mesh. mRectagle[0] = top-left corner,
// mRectangle[1] = bottom-left, mRectangle[2] = top-right and mRectangle[3] // mRectangle[1] = bottom-left, mRectangle[2] = top-right and mRectangle[3]
@ -268,7 +268,7 @@ public class CurlMesh {
// Also vertices/lines are given in an order first one has x -coordinate // Also vertices/lines are given in an order first one has x -coordinate
// at least the latter one. This property is used in getIntersections to // at least the latter one. This property is used in getIntersections to
// see if there is an intersection. // see if there is an intersection.
int lines[][] = {{0, 1}, {0, 2}, {1, 3}, {2, 3}}; int[][] lines = {{0, 1}, {0, 2}, {1, 3}, {2, 3}};
{ {
// TODO: There really has to be more 'easier' way of doing this - // TODO: There really has to be more 'easier' way of doing this -
// not including extensive use of sqrt. // not including extensive use of sqrt.
@ -826,8 +826,8 @@ public class CurlMesh {
* Simple fixed size array implementation. * Simple fixed size array implementation.
*/ */
private class Array<T> { private class Array<T> {
private Object[] mArray; private final Object[] mArray;
private int mCapacity; private final int mCapacity;
private int mSize; private int mSize;
public Array(int capacity) { public Array(int capacity) {

@ -2,7 +2,6 @@ package io.legado.app.ui.book.read.page.provider
import android.graphics.Rect import android.graphics.Rect
import android.text.Layout import android.text.Layout
import android.text.StaticLayout
import android.text.TextPaint import android.text.TextPaint
import io.legado.app.utils.toStringArray import io.legado.app.utils.toStringArray
import kotlin.math.max import kotlin.math.max

@ -13,7 +13,7 @@ data class SearchResult(
var chapterIndex: Int = 0, var chapterIndex: Int = 0,
var pageIndex: Int = 0, var pageIndex: Int = 0,
var newPosition: Int = 0, var newPosition: Int = 0,
var contentPosition: Int =0 var contentPosition: Int = 0
) { ) {
fun getHtmlCompat(textColor: String, accentColor: String): Spanned { fun getHtmlCompat(textColor: String, accentColor: String): Spanned {

@ -26,7 +26,7 @@ class BookSourceDebugModel(application: Application) : BaseViewModel(application
} }
} }
fun observe(callback: (Int, String)-> Unit){ fun observe(callback: (Int, String) -> Unit) {
this.callback = callback this.callback = callback
} }

@ -58,7 +58,12 @@ class BookSourceEditAdapter : RecyclerView.Adapter<BookSourceEditAdapter.MyViewH
editText.setText(editEntity.value) editText.setText(editEntity.value)
textInputLayout.hint = itemView.context.getString(editEntity.hint) textInputLayout.hint = itemView.context.getString(editEntity.hint)
val textWatcher = object : TextWatcher { val textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun beforeTextChanged(
s: CharSequence,
start: Int,
count: Int,
after: Int
) {
} }

@ -83,8 +83,8 @@ class BookmarkFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_bookmark
editView.setText(bookmark.content) editView.setText(bookmark.content)
editBookText.textSize = 15f editBookText.textSize = 15f
editView.textSize = 15f editView.textSize = 15f
editBookText.maxLines= 6 editBookText.maxLines = 6
editView.maxLines= 6 editView.maxLines = 6
} }
customView { alertBinding.root } customView { alertBinding.root }
yesButton { yesButton {

@ -138,10 +138,12 @@ class FileAdapter(context: Context, val callBack: CallBack) :
* 是否显示返回主目录 * 是否显示返回主目录
*/ */
var isShowHomeDir: Boolean var isShowHomeDir: Boolean
/** /**
* 是否显示返回上一级 * 是否显示返回上一级
*/ */
var isShowUpDir: Boolean var isShowUpDir: Boolean
/** /**
* 是否显示隐藏的目录.开头 * 是否显示隐藏的目录.开头
*/ */

@ -93,8 +93,12 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
lp.flexBasisPercent = style.layout_flexBasisPercent lp.flexBasisPercent = style.layout_flexBasisPercent
lp.isWrapBefore = style.layout_wrapBefore lp.isWrapBefore = style.layout_wrapBefore
} }
tv.setOnClickListener { if (kind.url.isNullOrBlank()) {
callBack.openExplore(sourceUrl, kind.title, kind.url) tv.setOnClickListener(null)
} else {
tv.setOnClickListener {
callBack.openExplore(sourceUrl, kind.title, kind.url)
}
} }
} }
} }

@ -12,7 +12,6 @@ import io.legado.app.databinding.ItemFilletTextBinding
import io.legado.app.databinding.PopupKeyboardToolBinding import io.legado.app.databinding.PopupKeyboardToolBinding
class KeyboardToolPop( class KeyboardToolPop(
context: Context, context: Context,
private val chars: List<String>, private val chars: List<String>,

@ -72,8 +72,12 @@ class RotateLoading @JvmOverloads constructor(
R.styleable.RotateLoading_loading_width, R.styleable.RotateLoading_loading_width,
DEFAULT_WIDTH.dp DEFAULT_WIDTH.dp
) )
shadowPosition = typedArray.getInt(R.styleable.RotateLoading_shadow_position, DEFAULT_SHADOW_POSITION) shadowPosition = typedArray.getInt(
speedOfDegree = typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE) R.styleable.RotateLoading_shadow_position,
DEFAULT_SHADOW_POSITION
)
speedOfDegree =
typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE)
hideMode = when (typedArray.getInt(R.styleable.RotateLoading_hide_mode, 2)) { hideMode = when (typedArray.getInt(R.styleable.RotateLoading_hide_mode, 2)) {
1 -> INVISIBLE 1 -> INVISIBLE
else -> GONE else -> GONE

@ -11,9 +11,9 @@ import io.legado.app.databinding.DialogTextViewBinding
import io.legado.app.utils.getSize import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
import io.noties.markwon.Markwon import io.noties.markwon.Markwon
import io.noties.markwon.image.glide.GlideImagesPlugin
import io.noties.markwon.ext.tables.TablePlugin import io.noties.markwon.ext.tables.TablePlugin
import io.noties.markwon.html.HtmlPlugin import io.noties.markwon.html.HtmlPlugin
import io.noties.markwon.image.glide.GlideImagesPlugin
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

@ -6,7 +6,8 @@ import android.widget.TextView
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import io.legado.app.R import io.legado.app.R
class EditTextPreference(context: Context, attrs: AttributeSet) : androidx.preference.EditTextPreference(context, attrs) { class EditTextPreference(context: Context, attrs: AttributeSet) :
androidx.preference.EditTextPreference(context, attrs) {
init { init {
// isPersistent = true // isPersistent = true

@ -25,7 +25,6 @@ import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding import io.legado.app.utils.viewbindingdelegate.viewBinding
class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) { class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) {
private var iconNames: Array<CharSequence> private var iconNames: Array<CharSequence>
private val mEntryDrawables = arrayListOf<Drawable?>() private val mEntryDrawables = arrayListOf<Drawable?>()
@ -55,7 +54,17 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference
override fun onBindViewHolder(holder: PreferenceViewHolder?) { override fun onBindViewHolder(holder: PreferenceViewHolder?) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
val v = Preference.bindView<ImageView>(context, holder, icon, title, summary, widgetLayoutResource, R.id.preview, 50, 50) val v = Preference.bindView<ImageView>(
context,
holder,
icon,
title,
summary,
widgetLayoutResource,
R.id.preview,
50,
50
)
if (v is ImageView) { if (v is ImageView) {
val selectedIndex = findIndexOfValue(value) val selectedIndex = findIndexOfValue(value)
if (selectedIndex >= 0) { if (selectedIndex >= 0) {

@ -14,7 +14,8 @@ import io.legado.app.lib.theme.backgroundColor
import io.legado.app.utils.ColorUtils import io.legado.app.utils.ColorUtils
class PreferenceCategory(context: Context, attrs: AttributeSet) : PreferenceCategory(context, attrs) { class PreferenceCategory(context: Context, attrs: AttributeSet) :
PreferenceCategory(context, attrs) {
init { init {
isPersistent = true isPersistent = true

@ -136,10 +136,14 @@ class DragSelectTouchHelper(
View.OnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> View.OnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
if (oldLeft != left || oldRight != right || oldTop != top || oldBottom != bottom) { if (oldLeft != left || oldRight != right || oldTop != top || oldBottom != bottom) {
if (v === mRecyclerView) { if (v === mRecyclerView) {
Logger.i("onLayoutChange:new: " Logger.i(
+ left + " " + top + " " + right + " " + bottom) "onLayoutChange:new: "
Logger.i("onLayoutChange:old: " + left + " " + top + " " + right + " " + bottom
+ oldLeft + " " + oldTop + " " + oldRight + " " + oldBottom) )
Logger.i(
"onLayoutChange:old: "
+ oldLeft + " " + oldTop + " " + oldRight + " " + oldBottom
)
init(bottom - top) init(bottom - top)
} }
} }
@ -203,8 +207,10 @@ class DragSelectTouchHelper(
private val mOnItemTouchListener: OnItemTouchListener by lazy { private val mOnItemTouchListener: OnItemTouchListener by lazy {
object : OnItemTouchListener { object : OnItemTouchListener {
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
Logger.d("onInterceptTouchEvent: x:" + e.x + ",y:" + e.y Logger.d(
+ ", " + MotionEvent.actionToString(e.action)) "onInterceptTouchEvent: x:" + e.x + ",y:" + e.y
+ ", " + MotionEvent.actionToString(e.action)
)
val adapter = rv.adapter val adapter = rv.adapter
if (adapter == null || adapter.itemCount == 0) { if (adapter == null || adapter.itemCount == 0) {
return false return false
@ -267,8 +273,10 @@ class DragSelectTouchHelper(
if (!isActivated) { if (!isActivated) {
return return
} }
Logger.d("onTouchEvent: x:" + e.x + ",y:" + e.y Logger.d(
+ ", " + MotionEvent.actionToString(e.action)) "onTouchEvent: x:" + e.x + ",y:" + e.y
+ ", " + MotionEvent.actionToString(e.action)
)
val action = e.action val action = e.action
when (action and MotionEvent.ACTION_MASK) { when (action and MotionEvent.ACTION_MASK) {
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
@ -506,8 +514,10 @@ class DragSelectTouchHelper(
mBottomRegionFrom = (rvHeight shr 1.toFloat().toInt()).toFloat() mBottomRegionFrom = (rvHeight shr 1.toFloat().toInt()).toFloat()
mTopRegionTo = mBottomRegionFrom mTopRegionTo = mBottomRegionFrom
} }
Logger.d("Hotspot: [" + mTopRegionFrom + ", " + mTopRegionTo + "], [" Logger.d(
+ mBottomRegionFrom + ", " + mBottomRegionTo + "]") "Hotspot: [" + mTopRegionFrom + ", " + mTopRegionTo + "], ["
+ mBottomRegionFrom + ", " + mBottomRegionTo + "]"
)
} }
private fun activeSelectInternal(position: Int) { private fun activeSelectInternal(position: Int) {
@ -613,12 +623,14 @@ class DragSelectTouchHelper(
SELECT_STATE_DRAG_FROM_NORMAL -> mSelectState = if (mShouldAutoChangeState) { SELECT_STATE_DRAG_FROM_NORMAL -> mSelectState = if (mShouldAutoChangeState) {
Logger.logSelectStateChange( Logger.logSelectStateChange(
mSelectState, mSelectState,
SELECT_STATE_SLIDE) SELECT_STATE_SLIDE
)
SELECT_STATE_SLIDE SELECT_STATE_SLIDE
} else { } else {
Logger.logSelectStateChange( Logger.logSelectStateChange(
mSelectState, mSelectState,
SELECT_STATE_NORMAL) SELECT_STATE_NORMAL
)
SELECT_STATE_NORMAL SELECT_STATE_NORMAL
} }
SELECT_STATE_DRAG_FROM_SLIDE -> { SELECT_STATE_DRAG_FROM_SLIDE -> {
@ -705,8 +717,10 @@ class DragSelectTouchHelper(
} }
private fun dp2px(dpVal: Float): Int { private fun dp2px(dpVal: Float): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, return TypedValue.applyDimension(
dpVal, mDisplayMetrics).toInt() TypedValue.COMPLEX_UNIT_DIP,
dpVal, mDisplayMetrics
).toInt()
} }
private val isRtl: Boolean private val isRtl: Boolean
@ -848,8 +862,10 @@ class DragSelectTouchHelper(
if (isSelected) { if (isSelected) {
updateSelectState(position, true) updateSelectState(position, true)
} else { } else {
updateSelectState(position, updateSelectState(
mOriginalSelection.contains(getItemId(position))) position,
mOriginalSelection.contains(getItemId(position))
)
} }
} }
Mode.ToggleAndKeep -> { Mode.ToggleAndKeep -> {
@ -866,8 +882,10 @@ class DragSelectTouchHelper(
if (isSelected) { if (isSelected) {
updateSelectState(position, !mFirstWasSelected) updateSelectState(position, !mFirstWasSelected)
} else { } else {
updateSelectState(position, updateSelectState(
mOriginalSelection.contains(getItemId(position))) position,
mOriginalSelection.contains(getItemId(position))
)
} }
} }
else -> // SelectAndReverse Mode else -> // SelectAndReverse Mode

@ -42,11 +42,15 @@ class ItemTouchCallback(private val callback: Callback) : ItemTouchHelper.Callba
/** /**
* 当用户拖拽或者滑动Item的时候需要我们告诉系统滑动或者拖拽的方向 * 当用户拖拽或者滑动Item的时候需要我们告诉系统滑动或者拖拽的方向
*/ */
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val layoutManager = recyclerView.layoutManager val layoutManager = recyclerView.layoutManager
if (layoutManager is GridLayoutManager) {// GridLayoutManager if (layoutManager is GridLayoutManager) {// GridLayoutManager
// flag如果值是0,相当于这个功能被关闭 // flag如果值是0,相当于这个功能被关闭
val dragFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN val dragFlag =
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlag = 0 val swipeFlag = 0
// create make // create make
return makeMovementFlags(dragFlag, swipeFlag) return makeMovementFlags(dragFlag, swipeFlag)

@ -91,7 +91,11 @@ class FastScroller : LinearLayout {
} }
@JvmOverloads @JvmOverloads
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(
context,
attrs,
defStyleAttr
) {
layout(context, attrs) layout(context, attrs)
layoutParams = generateLayoutParams(attrs) layoutParams = generateLayoutParams(attrs)
} }
@ -104,16 +108,32 @@ class FastScroller : LinearLayout {
fun setLayoutParams(viewGroup: ViewGroup) { fun setLayoutParams(viewGroup: ViewGroup) {
@IdRes val recyclerViewId = mRecyclerView?.id ?: View.NO_ID @IdRes val recyclerViewId = mRecyclerView?.id ?: View.NO_ID
val marginTop = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_top) val marginTop = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_top)
val marginBottom = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_bottom) val marginBottom =
resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_bottom)
require(recyclerViewId != View.NO_ID) { "RecyclerView must have a view ID" } require(recyclerViewId != View.NO_ID) { "RecyclerView must have a view ID" }
when (viewGroup) { when (viewGroup) {
is ConstraintLayout -> { is ConstraintLayout -> {
val constraintSet = ConstraintSet() val constraintSet = ConstraintSet()
@IdRes val layoutId = id @IdRes val layoutId = id
constraintSet.clone(viewGroup) constraintSet.clone(viewGroup)
constraintSet.connect(layoutId, ConstraintSet.TOP, recyclerViewId, ConstraintSet.TOP) constraintSet.connect(
constraintSet.connect(layoutId, ConstraintSet.BOTTOM, recyclerViewId, ConstraintSet.BOTTOM) layoutId,
constraintSet.connect(layoutId, ConstraintSet.END, recyclerViewId, ConstraintSet.END) ConstraintSet.TOP,
recyclerViewId,
ConstraintSet.TOP
)
constraintSet.connect(
layoutId,
ConstraintSet.BOTTOM,
recyclerViewId,
ConstraintSet.BOTTOM
)
constraintSet.connect(
layoutId,
ConstraintSet.END,
recyclerViewId,
ConstraintSet.END
)
constraintSet.applyTo(viewGroup) constraintSet.applyTo(viewGroup)
val layoutParams = layoutParams as ConstraintLayout.LayoutParams val layoutParams = layoutParams as ConstraintLayout.LayoutParams
layoutParams.setMargins(0, marginTop, 0, marginBottom) layoutParams.setMargins(0, marginTop, 0, marginBottom)
@ -359,8 +379,13 @@ class FastScroller : LinearLayout {
private fun setViewPositions(y: Float) { private fun setViewPositions(y: Float) {
mBubbleHeight = mBubbleView.height mBubbleHeight = mBubbleView.height
mHandleHeight = mHandleView.height mHandleHeight = mHandleView.height
val bubbleY = getValueInRange(0, mViewHeight - mBubbleHeight - mHandleHeight / 2, (y - mBubbleHeight).toInt()) val bubbleY = getValueInRange(
val handleY = getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt()) 0,
mViewHeight - mBubbleHeight - mHandleHeight / 2,
(y - mBubbleHeight).toInt()
)
val handleY =
getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt())
if (mShowBubble) { if (mShowBubble) {
mBubbleView.y = bubbleY.toFloat() mBubbleView.y = bubbleY.toFloat()
} }
@ -368,7 +393,8 @@ class FastScroller : LinearLayout {
} }
private fun updateViewHeights() { private fun updateViewHeights() {
val measureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) val measureSpec =
MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
mBubbleView.measure(measureSpec, measureSpec) mBubbleView.measure(measureSpec, measureSpec)
mBubbleHeight = mBubbleView.measuredHeight mBubbleHeight = mBubbleView.measuredHeight
mHandleView.measure(measureSpec, measureSpec) mHandleView.measure(measureSpec, measureSpec)
@ -427,7 +453,9 @@ class FastScroller : LinearLayout {
private fun showScrollbar() { private fun showScrollbar() {
mRecyclerView?.let { mRecyclerView -> mRecyclerView?.let { mRecyclerView ->
if (mRecyclerView.computeVerticalScrollRange() - mViewHeight > 0) { if (mRecyclerView.computeVerticalScrollRange() - mViewHeight > 0) {
val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() val transX =
resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end)
.toFloat()
mScrollbar.translationX = transX mScrollbar.translationX = transX
mScrollbar.visibility = View.VISIBLE mScrollbar.visibility = View.VISIBLE
mScrollbarAnimator = mScrollbar.animate().translationX(0f).alpha(1f) mScrollbarAnimator = mScrollbar.animate().translationX(0f).alpha(1f)
@ -441,7 +469,8 @@ class FastScroller : LinearLayout {
} }
private fun hideScrollbar() { private fun hideScrollbar() {
val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() val transX =
resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat()
mScrollbarAnimator = mScrollbar.animate().translationX(transX).alpha(0f) mScrollbarAnimator = mScrollbar.animate().translationX(transX).alpha(0f)
.setDuration(sScrollbarAnimDuration.toLong()) .setDuration(sScrollbarAnimDuration.toLong())
.setListener(object : AnimatorListenerAdapter() { .setListener(object : AnimatorListenerAdapter() {

@ -110,7 +110,9 @@ class BadgeView @JvmOverloads constructor(
val radius = dip2Px(dipRadius).toFloat() val radius = dip2Px(dipRadius).toFloat()
val radiusArray = val radiusArray =
floatArrayOf(radius, radius, radius, radius, radius, radius, radius, radius) floatArrayOf(radius, radius, radius, radius, radius, radius, radius, radius)
if (flatangle) { radiusArray.fill(0f, 0, 3) } if (flatangle) {
radiusArray.fill(0f, 0, 3)
}
val roundRect = RoundRectShape(radiusArray, null, null) val roundRect = RoundRectShape(radiusArray, null, null)
val bgDrawable = ShapeDrawable(roundRect) val bgDrawable = ShapeDrawable(roundRect)

@ -8,6 +8,6 @@ fun AlertDialog.applyTint(): AlertDialog {
return ATH.setAlertDialogTint(this) return ATH.setAlertDialogTint(this)
} }
fun AlertDialog.requestInputMethod(){ fun AlertDialog.requestInputMethod() {
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
} }

@ -31,7 +31,7 @@ object BitmapUtils {
val ips = FileInputStream(path) val ips = FileInputStream(path)
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true op.inJustDecodeBounds = true
BitmapFactory.decodeFileDescriptor(ips.fd,null,op) BitmapFactory.decodeFileDescriptor(ips.fd, null, op)
//获取比例大小 //获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt() val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt() val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
@ -44,7 +44,7 @@ object BitmapUtils {
} }
} }
op.inJustDecodeBounds = false op.inJustDecodeBounds = false
return BitmapFactory.decodeFileDescriptor(ips.fd,null,op) return BitmapFactory.decodeFileDescriptor(ips.fd, null, op)
} }
@ -57,10 +57,10 @@ object BitmapUtils {
val opts = BitmapFactory.Options() val opts = BitmapFactory.Options()
val ips = FileInputStream(path) val ips = FileInputStream(path)
opts.inJustDecodeBounds = true opts.inJustDecodeBounds = true
BitmapFactory.decodeFileDescriptor(ips.fd,null,opts) BitmapFactory.decodeFileDescriptor(ips.fd, null, opts)
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128) opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128)
opts.inJustDecodeBounds = false opts.inJustDecodeBounds = false
return BitmapFactory.decodeFileDescriptor(ips.fd,null,opts) return BitmapFactory.decodeFileDescriptor(ips.fd, null, opts)
} }
/** /**

@ -55,7 +55,7 @@ object FileUtils {
return file return file
} }
fun createFileWithReplace(filePath: String) : File{ fun createFileWithReplace(filePath: String): File {
val file = File(filePath) val file = File(filePath)
if (!file.exists()) { if (!file.exists()) {
//创建父类文件夹 //创建父类文件夹
@ -64,8 +64,7 @@ object FileUtils {
} }
//创建文件 //创建文件
file.createNewFile() file.createNewFile()
} } else {
else{
file.delete() file.delete()
file.createNewFile() file.createNewFile()
} }
@ -516,12 +515,13 @@ object FileUtils {
closeSilently(fos) closeSilently(fos)
} }
} }
/** /**
* 保存文件内容 * 保存文件内容
*/ */
fun writeInputStream(filepath: String, data: InputStream): Boolean { fun writeInputStream(filepath: String, data: InputStream): Boolean {
val file = File(filepath) val file = File(filepath)
return writeInputStream(file,data) return writeInputStream(file, data)
} }
/** /**
@ -534,7 +534,7 @@ object FileUtils {
file.parentFile?.mkdirs() file.parentFile?.mkdirs()
file.createNewFile() file.createNewFile()
} }
val buffer=ByteArray(1024*4) val buffer = ByteArray(1024 * 4)
fos = FileOutputStream(file) fos = FileOutputStream(file)
while (true) { while (true) {
val len = data.read(buffer, 0, buffer.size) val len = data.read(buffer, 0, buffer.size)

@ -4,12 +4,16 @@ import android.content.res.Resources
val Int.dp: Int val Int.dp: Int
get() = android.util.TypedValue.applyDimension( get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics android.util.TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
Resources.getSystem().displayMetrics
).toInt() ).toInt()
val Int.sp: Int val Int.sp: Int
get() = android.util.TypedValue.applyDimension( get() = android.util.TypedValue.applyDimension(
android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics android.util.TypedValue.COMPLEX_UNIT_SP,
this.toFloat(),
Resources.getSystem().displayMetrics
).toInt() ).toInt()
val Int.hexString: String val Int.hexString: String

@ -10,7 +10,9 @@ import com.google.android.material.snackbar.Snackbar
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("snackbar2") @JvmName("snackbar2")
fun View.snackbar(@StringRes message: Int) = Snackbar fun View.snackbar(
@StringRes message: Int
) = Snackbar
.make(this, message, Snackbar.LENGTH_SHORT) .make(this, message, Snackbar.LENGTH_SHORT)
.apply { show() } .apply { show() }
@ -20,7 +22,9 @@ fun View.snackbar(@StringRes message: Int) = Snackbar
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("longSnackbar2") @JvmName("longSnackbar2")
fun View.longSnackbar(@StringRes message: Int) = Snackbar fun View.longSnackbar(
@StringRes message: Int
) = Snackbar
.make(this, message, Snackbar.LENGTH_LONG) .make(this, message, Snackbar.LENGTH_LONG)
.apply { show() } .apply { show() }
@ -30,7 +34,9 @@ fun View.longSnackbar(@StringRes message: Int) = Snackbar
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("indefiniteSnackbar2") @JvmName("indefiniteSnackbar2")
fun View.indefiniteSnackbar(@StringRes message: Int) = Snackbar fun View.indefiniteSnackbar(
@StringRes message: Int
) = Snackbar
.make(this, message, Snackbar.LENGTH_INDEFINITE) .make(this, message, Snackbar.LENGTH_INDEFINITE)
.apply { show() } .apply { show() }
@ -40,7 +46,9 @@ fun View.indefiniteSnackbar(@StringRes message: Int) = Snackbar
* @param message the message text. * @param message the message text.
*/ */
@JvmName("snackbar2") @JvmName("snackbar2")
fun View.snackbar(message: CharSequence) = Snackbar fun View.snackbar(
message: CharSequence
) = Snackbar
.make(this, message, Snackbar.LENGTH_SHORT) .make(this, message, Snackbar.LENGTH_SHORT)
.apply { show() } .apply { show() }
@ -50,7 +58,9 @@ fun View.snackbar(message: CharSequence) = Snackbar
* @param message the message text. * @param message the message text.
*/ */
@JvmName("longSnackbar2") @JvmName("longSnackbar2")
fun View.longSnackbar(message: CharSequence) = Snackbar fun View.longSnackbar(
message: CharSequence
) = Snackbar
.make(this, message, Snackbar.LENGTH_LONG) .make(this, message, Snackbar.LENGTH_LONG)
.apply { show() } .apply { show() }
@ -60,7 +70,9 @@ fun View.longSnackbar(message: CharSequence) = Snackbar
* @param message the message text. * @param message the message text.
*/ */
@JvmName("indefiniteSnackbar2") @JvmName("indefiniteSnackbar2")
fun View.indefiniteSnackbar(message: CharSequence) = Snackbar fun View.indefiniteSnackbar(
message: CharSequence
) = Snackbar
.make(this, message, Snackbar.LENGTH_INDEFINITE) .make(this, message, Snackbar.LENGTH_INDEFINITE)
.apply { show() } .apply { show() }
@ -70,7 +82,11 @@ fun View.indefiniteSnackbar(message: CharSequence) = Snackbar
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("snackbar2") @JvmName("snackbar2")
fun View.snackbar(message: Int, @StringRes actionText: Int, action: (View) -> Unit) = Snackbar fun View.snackbar(
message: Int,
@StringRes actionText:
Int, action: (View) -> Unit
) = Snackbar
.make(this, message, Snackbar.LENGTH_SHORT) .make(this, message, Snackbar.LENGTH_SHORT)
.setAction(actionText, action) .setAction(actionText, action)
.apply { show() } .apply { show() }
@ -81,8 +97,11 @@ fun View.snackbar(message: Int, @StringRes actionText: Int, action: (View) -> Un
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("longSnackbar2") @JvmName("longSnackbar2")
fun View.longSnackbar(@StringRes message: Int, @StringRes actionText: Int, action: (View) -> Unit) = fun View.longSnackbar(
Snackbar @StringRes message: Int,
@StringRes actionText: Int,
action: (View) -> Unit
) = Snackbar
.make(this, message, Snackbar.LENGTH_LONG) .make(this, message, Snackbar.LENGTH_LONG)
.setAction(actionText, action) .setAction(actionText, action)
.apply { show() } .apply { show() }
@ -93,8 +112,11 @@ fun View.longSnackbar(@StringRes message: Int, @StringRes actionText: Int, actio
* @param message the message text resource. * @param message the message text resource.
*/ */
@JvmName("indefiniteSnackbar2") @JvmName("indefiniteSnackbar2")
fun View.indefiniteSnackbar(@StringRes message: Int, @StringRes actionText: Int, action: (View) -> Unit) = fun View.indefiniteSnackbar(
Snackbar @StringRes message: Int,
@StringRes actionText: Int,
action: (View) -> Unit
) = Snackbar
.make(this, message, Snackbar.LENGTH_INDEFINITE) .make(this, message, Snackbar.LENGTH_INDEFINITE)
.setAction(actionText, action) .setAction(actionText, action)
.apply { show() } .apply { show() }
@ -105,8 +127,11 @@ fun View.indefiniteSnackbar(@StringRes message: Int, @StringRes actionText: Int,
* @param message the message text. * @param message the message text.
*/ */
@JvmName("snackbar2") @JvmName("snackbar2")
fun View.snackbar(message: CharSequence, actionText: CharSequence, action: (View) -> Unit) = fun View.snackbar(
Snackbar message: CharSequence,
actionText: CharSequence,
action: (View) -> Unit
) = Snackbar
.make(this, message, Snackbar.LENGTH_SHORT) .make(this, message, Snackbar.LENGTH_SHORT)
.setAction(actionText, action) .setAction(actionText, action)
.apply { show() } .apply { show() }
@ -117,8 +142,11 @@ fun View.snackbar(message: CharSequence, actionText: CharSequence, action: (View
* @param message the message text. * @param message the message text.
*/ */
@JvmName("longSnackbar2") @JvmName("longSnackbar2")
fun View.longSnackbar(message: CharSequence, actionText: CharSequence, action: (View) -> Unit) = fun View.longSnackbar(
Snackbar message: CharSequence,
actionText: CharSequence,
action: (View) -> Unit
) = Snackbar
.make(this, message, Snackbar.LENGTH_LONG) .make(this, message, Snackbar.LENGTH_LONG)
.setAction(actionText, action) .setAction(actionText, action)
.apply { show() } .apply { show() }

Loading…
Cancel
Save