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. 7
      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. 20
      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. 14
      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. 118
      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. 40
      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. 2
      app/src/main/java/io/legado/app/ui/widget/recycler/LoadMoreView.kt
  60. 49
      app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt
  61. 4
      app/src/main/java/io/legado/app/ui/widget/text/BadgeView.kt
  62. 2
      app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt
  63. 8
      app/src/main/java/io/legado/app/utils/BitmapUtils.kt
  64. 10
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  65. 8
      app/src/main/java/io/legado/app/utils/IntExtensions.kt
  66. 58
      app/src/main/java/io/legado/app/utils/Snackbars.kt

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

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

@ -5,7 +5,8 @@ import android.animation.ObjectAnimator
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> =
arrayOf(ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f))

@ -5,7 +5,8 @@ import android.animation.ObjectAnimator
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> {
val scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f)

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

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

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

@ -38,41 +38,41 @@ data class SearchBook(
var time: Long = System.currentTimeMillis(),
var variable: String? = null,
var originOrder: Int = 0
): Parcelable, BaseBook, Comparable<SearchBook> {
) : Parcelable, BaseBook, Comparable<SearchBook> {
@Ignore
@IgnoredOnParcel
override var infoHtml: String? = null
@Ignore
@IgnoredOnParcel
override var tocHtml: String? = null
override fun equals(other: Any?) = other is SearchBook && other.bookUrl == bookUrl
override fun hashCode() = bookUrl.hashCode()
override fun compareTo(other: SearchBook): Int {
return other.originOrder - this.originOrder
}
@delegate:Transient
@delegate:Ignore
@IgnoredOnParcel
override val variableMap by lazy {
GSON.fromJsonObject<HashMap<String, String>>(variable) ?: HashMap()
}
override fun putVariable(key: String, value: String) {
variableMap[key] = value
variable = GSON.toJson(variableMap)
}
@delegate:Transient
@delegate:Ignore
@IgnoredOnParcel
val origins: LinkedHashSet<String> by lazy { linkedSetOf(origin) }
fun addOrigin(origin: String) {
origins.add(origin)
}

@ -10,7 +10,7 @@ import splitties.init.appCtx
@Suppress("MemberVisibilityCanBePrivate")
object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val isGooglePlay = appCtx.channel == "google"
val isCronet= appCtx.channel=="cronet"
val isCronet = appCtx.channel == "cronet"
var userAgent: String = getPrefUserAgent()
var isEInkMode = appCtx.getPrefString(PreferKey.themeMode) == "3"
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)
@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)
//图片缩小1/2
val width = (min(outWidth, transform.width) / 2f).roundToInt()

@ -190,7 +190,7 @@ object BookHelp {
}
fun getContent(book: Book, bookChapter: BookChapter): String? {
if (book.isLocalTxt()||book.isUmd()) {
if (book.isLocalTxt() || book.isUmd()) {
return LocalBook.getContext(book, bookChapter)
} else if (book.isEpub() && !hasContent(book, bookChapter)) {
val string = LocalBook.getContext(book, bookChapter)
@ -203,7 +203,7 @@ object BookHelp {
).writeText(it)
}
return string
}else {
} else {
val file = FileUtils.getFile(
downloadDir,
cacheFolderName,
@ -329,15 +329,15 @@ object BookHelp {
private val chapterNamePattern1 by lazy {
Pattern.compile(".*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)[章节篇回集话]")
}
private val chapterNamePattern2 by lazy {
Pattern.compile("^(?:[\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+[,:、])*([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+)(?:[,:、]|\\.[^\\d])")
}
private val regexA by lazy {
return@lazy "\\s".toRegex()
}
private fun getChapterNum(chapterName: String?): Int {
chapterName ?: return -1
val chapterName1 = StringUtils.fullToHalf(chapterName).replace(regexA, "")
@ -346,7 +346,7 @@ object BookHelp {
chapterNamePattern1.matcher(chapterName1).takeIf { it.find() }
?: chapterNamePattern2.matcher(chapterName1).takeIf { it.find() }
)?.group(1)
?:"-1"
?: "-1"
)
}
@ -366,7 +366,7 @@ object BookHelp {
//前后附加内容,整个章节名都在括号中时只剔除首尾括号,避免将章节名替换为空字串
return@lazy "(?!^)(?:[〖【《〔\\[{(][^〖【《〔\\[{()〕》】〗\\]}]+)?[)〕》】〗\\]}]$|^[〖【《〔\\[{(](?:[^〖【《〔\\[{()〕》】〗\\]}]+[〕》】〗\\]})])?(?!$)".toRegex()
}
private fun getPureChapterName(chapterName: String?): String {
return if (chapterName == null) "" else StringUtils.fullToHalf(chapterName)
.replace(regexA, "")

@ -5,7 +5,7 @@ import android.text.TextUtils
@Suppress("unused")
class EventMessage {
var what: Int?=null
var what: Int? = null
var tag: String? = 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 {
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()
chain.proceed(request)
})
if (AppConfig.isCronet){
builder.addInterceptor(CronetInterceptor())
}
if (AppConfig.isCronet) {
builder.addInterceptor(CronetInterceptor())
}
builder.build()

@ -79,7 +79,11 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书
* 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)
}
@ -88,7 +92,11 @@ object SSLHelper {
* bksFile password -> 客户端使用bks证书校验服务端证书
* 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)
}

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

@ -1,6 +1,9 @@
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
class CronetInterceptor : Interceptor {

@ -22,6 +22,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
eventListener: EventListener? = null,
responseCallback: Callback? = null
) : UrlRequest.Callback() {
private val eventListener: EventListener?
private val responseCallback: Callback?
private var followCount = 0
@ -37,7 +38,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
if (mException != null) {
throw mException as IOException
}
return mResponse
return this.mResponse
}
override fun onRedirectReceived(
@ -62,7 +63,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
}
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")
// sb.append("[Cached:").append(info.wasCached()).append("][StatusCode:")
// .append(info.httpStatusCode).append("][StatusText:").append(info.httpStatusText)
@ -74,7 +75,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
// }
// Log.e("Cronet", sb.toString())
if (eventListener != null) {
eventListener.responseHeadersEnd(mCall, mResponse)
eventListener.responseHeadersEnd(mCall, this.mResponse)
eventListener.responseBodyStart(mCall)
}
request.read(ByteBuffer.allocateDirect(32 * 1024))
@ -99,34 +100,43 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
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()
val responseBody: ResponseBody =
mBytesReceived.toByteArray().toResponseBody(contentType)
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()
eventListener?.callEnd(mCall)
if (responseCallback != null) {
try {
responseCallback.onResponse(mCall, mResponse)
responseCallback.onResponse(mCall, this.mResponse)
} catch (e: IOException) {
// Pass?
}
}
}
override fun onFailed(request: UrlRequest, info: UrlResponseInfo, error: CronetException) {
val e = IOException("Cronet Exception Occurred", error)
//UrlResponseInfo可能为null
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
mResponseCondition.open()
eventListener?.callFailed(mCall, e)
this.eventListener?.callFailed(mCall, e)
responseCallback?.onFailure(mCall, e)
}
override fun onCanceled(request: UrlRequest, info: UrlResponseInfo) {
mResponseCondition.open()
eventListener?.callEnd(mCall)
this.eventListener?.callEnd(mCall)
}
companion object {
@ -194,7 +204,7 @@ class CronetUrlRequestCallback @JvmOverloads internal constructor(
}
init {
mResponse = Response.Builder()
this.mResponse = Response.Builder()
.sentRequestAtMillis(System.currentTimeMillis())
.request(originalRequest)
.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) }
}
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) }
}
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) }
}
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) }
}

@ -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> =
AndroidAlertBuilder(this).apply { init() }

@ -52,7 +52,7 @@ public class CharsetDetector {
// wants the data, and doesn't care about a char set name.
/**
* Constructor
* Constructor
*
* @stable ICU 3.4
*/
@ -61,18 +61,17 @@ public class CharsetDetector {
/**
* Set the declared encoding for charset detection.
* The declared encoding of an input text is an encoding obtained
* from an http header or xml declaration or similar source that
* can be provided as additional information to the charset detector.
* A match between a declared encoding and a possible detected encoding
* will raise the quality of that detected encoding by a small delta,
* and will also appear as a "reason" for the match.
* The declared encoding of an input text is an encoding obtained
* from an http header or xml declaration or similar source that
* can be provided as additional information to the charset detector.
* A match between a declared encoding and a possible detected encoding
* will raise the quality of that detected encoding by a small delta,
* and will also appear as a "reason" for the match.
* <p>
* A declared encoding that is incompatible with the input data being
* 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
*/
public CharsetDetector setDeclaredEncoding(String encoding) {
@ -84,9 +83,7 @@ public class CharsetDetector {
* Set the input text (byte) data whose charset is to be detected.
*
* @param in the input text of unknown encoding
*
* @return This CharsetDetector
*
* @stable ICU 3.4
*/
public CharsetDetector setText(byte[] in) {
@ -100,17 +97,15 @@ public class CharsetDetector {
/**
* Set the input text (byte) data whose charset is to be detected.
* <p>
* The input stream that supplies the character data must have markSupported()
* == true; the charset detection process 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>
* The input stream that supplies the character data must have markSupported()
* == true; the charset detection process 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.
*
* @param in the input text of unknown encoding
*
* @return This CharsetDetector
*
* @stable ICU 3.4
*/
@ -139,21 +134,20 @@ public class CharsetDetector {
/**
* Return the charset that best matches the supplied input data.
*
* Note though, that because the detection
* <p>
* Note though, that because the detection
* only looks at the start of the input data,
* there is a possibility that the returned charset will fail to handle
* the full set of input data.
* <p>
* Raise an exception if
* <ul>
* <li>no charset appears to match the data.</li>
* <li>no input text has been provided</li>
* </ul>
* p>
* aise an exception if
* <ul>
* <li>no charset appears to match the data.</li>
* <li>no input text has been provided</li>
* </ul>
*
* @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
*/
public CharsetMatch detect() {
@ -171,18 +165,17 @@ public class CharsetDetector {
}
/**
* Return an array of all charsets that appear to be plausible
* matches with the input data. The array is ordered with the
* best quality match first.
* Return an array of all charsets that appear to be plausible
* matches with the input data. The array is ordered with the
* best quality match first.
* <p>
* Raise an exception if
* <ul>
* <li>no charsets appear to match the input data.</li>
* <li>no input text has been provided</li>
* </ul>
* aise an exception if
* <ul>
* <li>no charsets appear to match the input data.</li>
* <li>no input text has been provided</li>
* </ul>
*
* @return An array of CharsetMatch objects representing possibly matching charsets.
*
* @stable ICU 3.4
*/
public CharsetMatch[] detectAll() {
@ -215,21 +208,19 @@ public class CharsetDetector {
* to access the converted input data.
* <p>
* 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>
* 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.
*
* @param in The source of the byte data in the unknown charset.
*
* @param declaredEncoding A declared encoding for the data, if available,
* or null or an empty string if none is available.
*
* @param in The source of the byte data in the unknown charset.
* @param declaredEncoding A declared encoding for the data, if available,
* or null or an empty string if none is available.
* @stable ICU 3.4
*/
public Reader getReader(InputStream in, String declaredEncoding) {
@ -255,15 +246,13 @@ public class CharsetDetector {
* containing the converted input data.
* <p>
* This is a convenience method that is equivalent to
* <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getString();</code>
*<p>
* <code>this.setDeclaredEncoding(declaredEncoding).setText(in).detect().getString();</code>
* <p>
* 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 declaredEncoding A declared encoding for the data, if available,
* or null or an empty string if none is available.
*
* @param in The source of the byte data in the unknown charset.
* @param declaredEncoding A declared encoding for the data, if available,
* or null or an empty string if none is available.
* @stable ICU 3.4
*/
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
* <code>CharsetDetector</code> class.
*
* @stable ICU 3.4
*/
public static String[] getAllDetectableCharsets() {
@ -312,10 +300,8 @@ public class CharsetDetector {
* Test whether or not input filtering is enabled.
*
* @return <code>true</code> if input text will be filtered.
*
* @see #enableInputFilter
*
* @stable ICU 3.4
* @see #enableInputFilter
*/
public boolean inputFilterEnabled() {
return fStripTags;
@ -327,9 +313,7 @@ public class CharsetDetector {
* before detection.
*
* @param filter <code>true</code> to enable input text filtering.
*
* @return The previous setting.
*
* @stable ICU 3.4
*/
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
* instance.
*
* @internal
* @deprecated This API is ICU internal only.
*/
@ -540,12 +523,11 @@ public class CharsetDetector {
* {@link #getAllDetectableCharsets()}.
*
* @param encoding the name of charset encoding.
* @param enabled <code>true</code> to enable, or <code>false</code> to disable the
* charset encoding.
* @param enabled <code>true</code> to enable, or <code>false</code> to disable the
* charset encoding.
* @return A reference to this <code>CharsetDetector</code>.
* @throws IllegalArgumentException when the name of charset encoding is
* not supported.
*
* not supported.
* @internal
* @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.
*
* @return the Reader for the Unicode character data.
*
* @stable ICU 3.4
*/
public Reader getReader() {
@ -65,7 +64,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* to the original byte data supplied to the Charset detect operation.
*
* @return a String created from the converted input data.
*
* @stable ICU 3.4
*/
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
* unlimited length.
* @return a String created from the converted input data.
*
* @stable ICU 3.4
*/
public String getString(int maxLength) throws java.io.IOException {
@ -128,7 +125,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* charset.
*
* @return the confidence in the charset match
*
* @stable ICU 3.4
*/
public int getConfidence() {
@ -143,12 +139,10 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* charsets that are registered with the IANA charset registry,
* this is the MIME-preferred registerd name.
*
* @see java.nio.charset.Charset
* @see java.io.InputStreamReader
*
* @return The name of the charset.
*
* @stable ICU 3.4
* @see java.nio.charset.Charset
* @see java.io.InputStreamReader
*/
public String getName() {
return fCharsetName;
@ -158,7 +152,6 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* 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.
*
* @stable ICU 3.4
*/
public String getLanguage() {
@ -168,13 +161,13 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
/**
* Compare to other CharsetMatch objects.
* 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.
* @return a negative integer, zero, or a positive integer as the
* confidence level of this CharsetMatch
* is less than, equal to, or greater than that of
* the argument.
* confidence level of this CharsetMatch
* is less than, equal to, or greater than that of
* the argument.
* @throws ClassCastException if the argument is not a CharsetMatch.
* @stable ICU 4.4
*/
@ -233,7 +226,7 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
//
// Private Data
//
private int fConfidence;
private final int fConfidence;
private byte[] fRawInput = null; // Original, untouched input bytes.
// If user gave us a byte array, this is it.
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
// 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.
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.
}

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

@ -29,7 +29,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
protected int byteIndex = 0;
private int ngram = 0;
private int[] ngramList;
private final int[] ngramList;
protected byte[] byteMap;
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(
"da",
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,
};
private static NGramsPlusLang[] ngrams_8859_2 = new NGramsPlusLang[]{
private static final NGramsPlusLang[] ngrams_8859_2 = new NGramsPlusLang[]{
new NGramsPlusLang(
"cs",
new int[]{
@ -568,7 +568,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -630,7 +630,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -692,7 +692,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -755,7 +755,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -781,7 +781,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -845,7 +845,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -866,14 +866,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
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,
@ -926,14 +926,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
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,
@ -986,14 +986,14 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
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,
@ -1078,7 +1078,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
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,
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,
@ -1098,7 +1098,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
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,
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,
@ -1144,7 +1144,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,
@ -1165,7 +1165,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
}
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,
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,

@ -25,12 +25,14 @@ package io.legado.app.lib.icu4j;
abstract class CharsetRecognizer {
/**
* Get the IANA name of this charset.
*
* @return the charset name.
*/
abstract String getName();
/**
* Get the ISO language code for this charset.
*
* @return the language code, or <code>null</code> if the language cannot be determined.
*/
public String getLanguage() {
@ -39,12 +41,12 @@ abstract class CharsetRecognizer {
/**
* 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
* to be checked for being in this charset.
* @param det The CharsetDetector, which contains the input text
* to be checked for being in this charset.
* @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);

@ -14,7 +14,10 @@ import androidx.core.graphics.drawable.DrawableCompat
@Suppress("unused")
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))
}
@ -27,7 +30,11 @@ object DrawableUtils {
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 {
val wrappedDrawable = DrawableCompat.wrap(it)
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 {
val wrappedDrawable = DrawableCompat.wrap(it)
wrappedDrawable.mutate()

@ -11,17 +11,31 @@ import com.google.android.material.navigation.NavigationView
@Suppress("unused")
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(
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)
)
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(
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)
)
navigationView.itemTextColor = textSl

@ -63,7 +63,12 @@ object Selector {
private var hasSetFocusedStrokeColor = 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
init {

@ -5,28 +5,28 @@ package io.legado.app.lib.theme
*/
object ThemeStorePrefKeys {
const val CONFIG_PREFS_KEY_DEFAULT = "app_themes"
const val IS_CONFIGURED_KEY = "is_configured"
const val IS_CONFIGURED_VERSION_KEY = "is_configured_version"
const val VALUES_CHANGED = "values_changed"
const val CONFIG_PREFS_KEY_DEFAULT = "app_themes"
const val IS_CONFIGURED_KEY = "is_configured"
const val IS_CONFIGURED_VERSION_KEY = "is_configured_version"
const val VALUES_CHANGED = "values_changed"
const val KEY_PRIMARY_COLOR = "primary_color"
const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark"
const val KEY_ACCENT_COLOR = "accent_color"
const val KEY_STATUS_BAR_COLOR = "status_bar_color"
const val KEY_NAVIGATION_BAR_COLOR = "navigation_bar_color"
const val KEY_PRIMARY_COLOR = "primary_color"
const val KEY_PRIMARY_COLOR_DARK = "primary_color_dark"
const val KEY_ACCENT_COLOR = "accent_color"
const val KEY_STATUS_BAR_COLOR = "status_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_INVERSE = "text_color_primary_inverse"
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_PRIMARY = "text_color_primary"
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_INVERSE = "text_color_secondary_inverse"
const val KEY_BACKGROUND_COLOR = "backgroundColor"
const val KEY_BOTTOM_BACKGROUND = "bottomBackground"
const val KEY_BACKGROUND_COLOR = "backgroundColor"
const val KEY_BOTTOM_BACKGROUND = "bottomBackground"
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar"
const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar"
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")
exploreDebug(scope, webBook, url)
}
key.startsWith("++")-> {
key.startsWith("++") -> {
val url = key.substring(2)
val book = Book()
book.origin = webBook.sourceUrl
@ -132,7 +132,7 @@ object Debug {
log(webBook.sourceUrl, "⇒开始访目录页:$url")
tocDebug(scope, webBook, book)
}
key.startsWith("--")-> {
key.startsWith("--") -> {
val url = key.substring(2)
val book = Book()
book.origin = webBook.sourceUrl

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

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

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

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

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

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

@ -86,8 +86,8 @@ class SearchBookModel(private val scope: CoroutineScope, private val callBack: C
} else {
searchIndex++
}
if (searchIndex >= bookSourceList.lastIndex + min(bookSourceList.size,
threadCount)
if (searchIndex >= bookSourceList.lastIndex
+ min(bookSourceList.size, threadCount)
) {
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.utils.postEvent
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors
import kotlin.math.min
@ -129,14 +130,14 @@ class CheckSourceService : BaseService() {
throw Exception("正文内容为空")
}
}.timeout(180000L)
.onError {
.onError(IO) {
source.addGroup("失效")
source.bookSourceComment = """
"error:${it.localizedMessage}
${source.bookSourceComment}"
""".trimIndent()
appDb.bookSourceDao.update(source)
}.onSuccess {
}.onSuccess(IO) {
source.removeGroup("失效")
source.bookSourceComment = source.bookSourceComment
?.split("\n")

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

@ -233,7 +233,11 @@ class CacheViewModel(application: Application) : BaseViewModel(application) {
}
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 = ""
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
class TextFontWeightConverter(context: Context, attrs: AttributeSet?) : StrokeTextView(context, attrs) {
class TextFontWeightConverter(context: Context, attrs: AttributeSet?) :
StrokeTextView(context, attrs) {
private val spannableString = SpannableString("中/粗/细")
private var enabledSpan: ForegroundColorSpan = ForegroundColorSpan(context.accentColor)

@ -23,20 +23,26 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
// 贝塞尔曲线起始点
private val mBezierStart1 = PointF()
// 贝塞尔曲线控制点
private val mBezierControl1 = PointF()
// 贝塞尔曲线顶点
private val mBezierVertex1 = PointF()
// 贝塞尔曲线结束点
private var mBezierEnd1 = PointF()
// 另一条贝塞尔曲线
// 贝塞尔曲线起始点
private val mBezierStart2 = PointF()
// 贝塞尔曲线控制点
private val mBezierControl2 = PointF()
// 贝塞尔曲线顶点
private val mBezierVertex2 = PointF()
// 贝塞尔曲线结束点
private var mBezierEnd2 = PointF()
@ -60,10 +66,13 @@ class SimulationPageDelegate(readView: ReadView) : HorizontalPageDelegate(readVi
// 是否属于右上左下
private var mIsRtOrLb = false
private var mMaxLength = hypot(viewWidth.toDouble(), viewHeight.toDouble()).toFloat()
// 背面颜色组
private var mBackShadowColors: IntArray
// 前面颜色组
private var mFrontShadowColors: IntArray
// 有阴影的GradientDrawable
private var mBackShadowDrawableLR: 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
// once here and reuse them on runtime. Doesn't really have very much effect
// but avoids some garbage collections from happening.
private Array<ShadowVertex> mArrDropShadowVertices;
private Array<Vertex> mArrIntersections;
private Array<Vertex> mArrOutputVertices;
private Array<Vertex> mArrRotatedVertices;
private Array<Double> mArrScanLines;
private Array<ShadowVertex> mArrSelfShadowVertices;
private Array<ShadowVertex> mArrTempShadowVertices;
private Array<Vertex> mArrTempVertices;
private final Array<ShadowVertex> mArrDropShadowVertices;
private final Array<Vertex> mArrIntersections;
private final Array<Vertex> mArrOutputVertices;
private final Array<Vertex> mArrRotatedVertices;
private final Array<Double> mArrScanLines;
private final Array<ShadowVertex> mArrSelfShadowVertices;
private final Array<ShadowVertex> mArrTempShadowVertices;
private final Array<Vertex> mArrTempVertices;
// Buffers for feeding rasterizer.
private FloatBuffer mBufColors;
private final FloatBuffer mBufColors;
private FloatBuffer mBufCurlPositionLines;
private FloatBuffer mBufShadowColors;
private FloatBuffer mBufShadowVertices;
private FloatBuffer mBufTexCoords;
private FloatBuffer mBufVertices;
private final FloatBuffer mBufShadowColors;
private final FloatBuffer mBufShadowVertices;
private final FloatBuffer mBufTexCoords;
private final FloatBuffer mBufVertices;
private int mCurlPositionLinesCount;
private int mDropShadowCount;
@ -66,7 +66,7 @@ public class CurlMesh {
// Boolean for 'flipping' texture sideways.
private boolean mFlipTexture = false;
// 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,
// 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
// at least the latter one. This property is used in getIntersections to
// 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 -
// not including extensive use of sqrt.
@ -826,8 +826,8 @@ public class CurlMesh {
* Simple fixed size array implementation.
*/
private class Array<T> {
private Object[] mArray;
private int mCapacity;
private final Object[] mArray;
private final int mCapacity;
private int mSize;
public Array(int capacity) {

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

@ -13,7 +13,7 @@ data class SearchResult(
var chapterIndex: Int = 0,
var pageIndex: Int = 0,
var newPosition: Int = 0,
var contentPosition: Int =0
var contentPosition: Int = 0
) {
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
}

@ -58,7 +58,12 @@ class BookSourceEditAdapter : RecyclerView.Adapter<BookSourceEditAdapter.MyViewH
editText.setText(editEntity.value)
textInputLayout.hint = itemView.context.getString(editEntity.hint)
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)
editBookText.textSize = 15f
editView.textSize = 15f
editBookText.maxLines= 6
editView.maxLines= 6
editBookText.maxLines = 6
editView.maxLines = 6
}
customView { alertBinding.root }
yesButton {

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

@ -93,8 +93,12 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
lp.flexBasisPercent = style.layout_flexBasisPercent
lp.isWrapBefore = style.layout_wrapBefore
}
tv.setOnClickListener {
callBack.openExplore(sourceUrl, kind.title, kind.url)
if (kind.url.isNullOrBlank()) {
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
class KeyboardToolPop(
context: Context,
private val chars: List<String>,

@ -72,8 +72,12 @@ class RotateLoading @JvmOverloads constructor(
R.styleable.RotateLoading_loading_width,
DEFAULT_WIDTH.dp
)
shadowPosition = typedArray.getInt(R.styleable.RotateLoading_shadow_position, DEFAULT_SHADOW_POSITION)
speedOfDegree = typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE)
shadowPosition = typedArray.getInt(
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)) {
1 -> INVISIBLE
else -> GONE

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

@ -6,7 +6,8 @@ import android.widget.TextView
import androidx.preference.PreferenceViewHolder
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 {
// isPersistent = true

@ -25,7 +25,6 @@ import io.legado.app.utils.getSize
import io.legado.app.utils.viewbindingdelegate.viewBinding
class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) {
private var iconNames: Array<CharSequence>
private val mEntryDrawables = arrayListOf<Drawable?>()
@ -55,7 +54,17 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference
override fun onBindViewHolder(holder: PreferenceViewHolder?) {
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) {
val selectedIndex = findIndexOfValue(value)
if (selectedIndex >= 0) {

@ -14,7 +14,8 @@ import io.legado.app.lib.theme.backgroundColor
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 {
isPersistent = true

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

@ -42,11 +42,15 @@ class ItemTouchCallback(private val callback: Callback) : ItemTouchHelper.Callba
/**
* 当用户拖拽或者滑动Item的时候需要我们告诉系统滑动或者拖拽的方向
*/
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
override fun getMovementFlags(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
val layoutManager = recyclerView.layoutManager
if (layoutManager is GridLayoutManager) {// GridLayoutManager
// 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
// create make
return makeMovementFlags(dragFlag, swipeFlag)

@ -29,7 +29,7 @@ class LoadMoreView(context: Context, attrs: AttributeSet? = null) : FrameLayout(
fun stopLoad() {
binding.rotateLoading.hide()
}
fun hasMore() {
hasMore = true
binding.tvText.invisible()

@ -91,7 +91,11 @@ class FastScroller : LinearLayout {
}
@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)
layoutParams = generateLayoutParams(attrs)
}
@ -104,16 +108,32 @@ class FastScroller : LinearLayout {
fun setLayoutParams(viewGroup: ViewGroup) {
@IdRes val recyclerViewId = mRecyclerView?.id ?: View.NO_ID
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" }
when (viewGroup) {
is ConstraintLayout -> {
val constraintSet = ConstraintSet()
@IdRes val layoutId = id
constraintSet.clone(viewGroup)
constraintSet.connect(layoutId, ConstraintSet.TOP, recyclerViewId, ConstraintSet.TOP)
constraintSet.connect(layoutId, ConstraintSet.BOTTOM, recyclerViewId, ConstraintSet.BOTTOM)
constraintSet.connect(layoutId, ConstraintSet.END, recyclerViewId, ConstraintSet.END)
constraintSet.connect(
layoutId,
ConstraintSet.TOP,
recyclerViewId,
ConstraintSet.TOP
)
constraintSet.connect(
layoutId,
ConstraintSet.BOTTOM,
recyclerViewId,
ConstraintSet.BOTTOM
)
constraintSet.connect(
layoutId,
ConstraintSet.END,
recyclerViewId,
ConstraintSet.END
)
constraintSet.applyTo(viewGroup)
val layoutParams = layoutParams as ConstraintLayout.LayoutParams
layoutParams.setMargins(0, marginTop, 0, marginBottom)
@ -359,8 +379,13 @@ class FastScroller : LinearLayout {
private fun setViewPositions(y: Float) {
mBubbleHeight = mBubbleView.height
mHandleHeight = mHandleView.height
val bubbleY = getValueInRange(0, mViewHeight - mBubbleHeight - mHandleHeight / 2, (y - mBubbleHeight).toInt())
val handleY = getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt())
val bubbleY = getValueInRange(
0,
mViewHeight - mBubbleHeight - mHandleHeight / 2,
(y - mBubbleHeight).toInt()
)
val handleY =
getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt())
if (mShowBubble) {
mBubbleView.y = bubbleY.toFloat()
}
@ -368,7 +393,8 @@ class FastScroller : LinearLayout {
}
private fun updateViewHeights() {
val measureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
val measureSpec =
MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
mBubbleView.measure(measureSpec, measureSpec)
mBubbleHeight = mBubbleView.measuredHeight
mHandleView.measure(measureSpec, measureSpec)
@ -427,7 +453,9 @@ class FastScroller : LinearLayout {
private fun showScrollbar() {
mRecyclerView?.let { mRecyclerView ->
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.visibility = View.VISIBLE
mScrollbarAnimator = mScrollbar.animate().translationX(0f).alpha(1f)
@ -441,7 +469,8 @@ class FastScroller : LinearLayout {
}
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)
.setDuration(sScrollbarAnimDuration.toLong())
.setListener(object : AnimatorListenerAdapter() {

@ -110,7 +110,9 @@ class BadgeView @JvmOverloads constructor(
val radius = dip2Px(dipRadius).toFloat()
val radiusArray =
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 bgDrawable = ShapeDrawable(roundRect)

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

@ -31,7 +31,7 @@ object BitmapUtils {
val ips = FileInputStream(path)
// inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight;
op.inJustDecodeBounds = true
BitmapFactory.decodeFileDescriptor(ips.fd,null,op)
BitmapFactory.decodeFileDescriptor(ips.fd, null, op)
//获取比例大小
val wRatio = ceil((op.outWidth / width).toDouble()).toInt()
val hRatio = ceil((op.outHeight / height).toDouble()).toInt()
@ -44,7 +44,7 @@ object BitmapUtils {
}
}
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 ips = FileInputStream(path)
opts.inJustDecodeBounds = true
BitmapFactory.decodeFileDescriptor(ips.fd,null,opts)
BitmapFactory.decodeFileDescriptor(ips.fd, null, opts)
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128)
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
}
fun createFileWithReplace(filePath: String) : File{
fun createFileWithReplace(filePath: String): File {
val file = File(filePath)
if (!file.exists()) {
//创建父类文件夹
@ -64,8 +64,7 @@ object FileUtils {
}
//创建文件
file.createNewFile()
}
else{
} else {
file.delete()
file.createNewFile()
}
@ -516,12 +515,13 @@ object FileUtils {
closeSilently(fos)
}
}
/**
* 保存文件内容
*/
fun writeInputStream(filepath: String, data: InputStream): Boolean {
val file = File(filepath)
return writeInputStream(file,data)
return writeInputStream(file, data)
}
/**
@ -534,7 +534,7 @@ object FileUtils {
file.parentFile?.mkdirs()
file.createNewFile()
}
val buffer=ByteArray(1024*4)
val buffer = ByteArray(1024 * 4)
fos = FileOutputStream(file)
while (true) {
val len = data.read(buffer, 0, buffer.size)

@ -4,12 +4,16 @@ import android.content.res.Resources
val Int.dp: Int
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()
val Int.sp: Int
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()
val Int.hexString: String

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

Loading…
Cancel
Save