This commit is contained in:
HapeLee committed 2025-06-04 13:33:51 +08:00
1 parent b86d90021c
commit 6c0757c91b
972 files changed
+6885 -7321

No files matched your search

@@ -0,0 +1,111 @@
package io.legato.kazusa.constant
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.provider.Settings
import androidx.annotation.Keep
import cn.hutool.crypto.digest.DigestUtil
import io.legato.kazusa.BuildConfig
import io.legato.kazusa.help.update.AppVariant
import org.apache.commons.lang3.time.FastDateFormat
import splitties.init.appCtx
@Suppress("ConstPropertyName")
@SuppressLint("SimpleDateFormat")
object AppConst {
const val APP_TAG = "Legado"
const val channelIdDownload = "channel_download"
const val channelIdReadAloud = "channel_read_aloud"
const val channelIdWeb = "channel_web"
const val UA_NAME = "User-Agent"
const val MAX_THREAD = 9
const val DEFAULT_WEBDAV_ID = -1L
private const val OFFICIAL_SIGNATURE =
"8DACBF25EC667C9B1374DB1450C1A866C2AAA1173016E80BF6AD2F06FABDDC08"
private const val BETA_SIGNATURE =
"93A28468B0F69E8D14C8A99AB45841CEF902BBBA3761BBFEE02E67CBA801563E"
val timeFormat: FastDateFormat by lazy {
FastDateFormat.getInstance("HH:mm")
}
val dateFormat: FastDateFormat by lazy {
FastDateFormat.getInstance("yyyy/MM/dd HH:mm")
}
val fileNameFormat: FastDateFormat by lazy {
FastDateFormat.getInstance("yy-MM-dd-HH-mm-ss")
}
const val imagePathKey = "imagePath"
val menuViewNames = arrayOf(
"com.android.internal.view.menu.ListMenuItemView",
"androidx.appcompat.view.menu.ListMenuItemView"
)
@SuppressLint("PrivateResource")
val sysElevation = appCtx.resources
.getDimension(com.google.android.material.R.dimen.design_appbar_elevation)
.toInt()
val androidId: String by lazy {
Settings.System.getString(appCtx.contentResolver, Settings.Secure.ANDROID_ID) ?: "null"
}
val appInfo: AppInfo by lazy {
val appInfo = AppInfo()
@Suppress("DEPRECATION")
appCtx.packageManager.getPackageInfo(appCtx.packageName, PackageManager.GET_ACTIVITIES)
?.let {
appInfo.versionName = it.versionName!!
appInfo.appVariant = when {
it.packageName.contains("releaseA") -> AppVariant.BETA_RELEASEA
isBeta -> AppVariant.BETA_RELEASE
isOfficial -> AppVariant.OFFICIAL
else -> AppVariant.UNKNOWN
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
appInfo.versionCode = it.longVersionCode
} else {
@Suppress("DEPRECATION")
appInfo.versionCode = it.versionCode.toLong()
}
}
appInfo
}
@Suppress("DEPRECATION")
private val sha256Signature: String by lazy {
val packageInfo =
appCtx.packageManager.getPackageInfo(appCtx.packageName, PackageManager.GET_SIGNATURES)
DigestUtil.sha256Hex(packageInfo.signatures!![0].toByteArray()).uppercase()
}
private val isOfficial = sha256Signature == OFFICIAL_SIGNATURE
private val isBeta = sha256Signature == BETA_SIGNATURE || BuildConfig.DEBUG
val charsets =
arrayListOf("UTF-8", "GB2312", "GB18030", "GBK", "Unicode", "UTF-16", "UTF-16LE", "ASCII")
@Keep
data class AppInfo(
var versionCode: Long = 0L,
var versionName: String = "",
var appVariant: AppVariant = AppVariant.UNKNOWN
)
/**
* The authority of a FileProvider defined in a <provider> element in your app's manifest.
*/
const val authority = BuildConfig.APPLICATION_ID + ".fileProvider"
}
@@ -0,0 +1,64 @@
package io.legato.kazusa.constant
import android.util.Log
import io.legato.kazusa.BuildConfig
import io.legato.kazusa.help.config.AppConfig
import io.legato.kazusa.utils.LogUtils
import io.legato.kazusa.utils.toastOnUi
import splitties.init.appCtx
object AppLog {
private val mLogs = arrayListOf<Triple<Long, String, Throwable?>>()
val logs get() = mLogs.toList()
@Synchronized
fun put(message: String?, throwable: Throwable? = null, toast: Boolean = false) {
message ?: return
if (toast) {
appCtx.toastOnUi(message)
}
if (mLogs.size > 100) {
mLogs.removeLastOrNull()
}
if (throwable == null) {
LogUtils.d("AppLog", message)
} else {
LogUtils.d("AppLog", "$message\n${throwable.stackTraceToString()}")
}
mLogs.add(0, Triple(System.currentTimeMillis(), message, throwable))
if (BuildConfig.DEBUG) {
val stackTrace = Thread.currentThread().stackTrace
Log.e(stackTrace[3].className, message, throwable)
}
}
@Synchronized
fun putNotSave(message: String?, throwable: Throwable? = null, toast: Boolean = false) {
message ?: return
if (toast) {
appCtx.toastOnUi(message)
}
if (mLogs.size > 100) {
mLogs.removeLastOrNull()
}
mLogs.add(0, Triple(System.currentTimeMillis(), message, throwable))
if (BuildConfig.DEBUG) {
val stackTrace = Thread.currentThread().stackTrace
Log.e(stackTrace[3].className, message, throwable)
}
}
@Synchronized
fun clear() {
mLogs.clear()
}
fun putDebug(message: String?, throwable: Throwable? = null) {
if (AppConfig.recordLog) {
put(message, throwable)
}
}
}
@@ -0,0 +1,57 @@
package io.legato.kazusa.constant
import java.util.regex.Pattern
@Suppress("RegExpRedundantEscape", "unused")
object AppPattern {
val JS_PATTERN: Pattern =
Pattern.compile("<js>([\\w\\W]*?)</js>|@js:([\\w\\W]*)", Pattern.CASE_INSENSITIVE)
val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}")
//匹配格式化后的图片格式
val imgPattern: Pattern = Pattern.compile("<img[^>]*src=\"([^\"]*(?:\"[^>]+\\})?)\"[^>]*>")
//dataURL图片类型
val dataUriRegex = Regex("^data:.*?;base64,(.*)")
val nameRegex = Regex("\\s+作\\s*者.*|\\s+\\S+\\s+著")
val authorRegex = Regex("^\\s*作\\s*者[::\\s]+|\\s+著")
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]")
val splitGroupRegex = Regex("[,;,;]")
val titleNumPattern: Pattern = Pattern.compile("(第)(.+?)(章)")
//书源调试信息中的各种符号
val debugMessageSymbolRegex = Regex("[⇒◇┌└≡]")
//本地书籍支持类型
val bookFileRegex = Regex(".*\\.(txt|epub|umd|pdf|mobi|azw3|azw)", RegexOption.IGNORE_CASE)
//压缩文件支持类型
val archiveFileRegex = Regex(".*\\.(zip|rar|7z)$", RegexOption.IGNORE_CASE)
/**
* 所有标点
*/
val bdRegex = Regex("(\\p{P})+")
/**
* 换行
*/
val rnRegex = Regex("[\\r\\n]")
/**
* 不发音段落判断
*/
val notReadAloudRegex = Regex("^(\\s|\\p{C}|\\p{P}|\\p{Z}|\\p{S})+$")
val xmlContentTypeRegex = "(application|text)/\\w*\\+?xml.*".toRegex()
val semicolonRegex = ";".toRegex()
val equalsRegex = "=".toRegex()
val spaceRegex = "\\s+".toRegex()
val regexCharRegex = "[{}()\\[\\].+*?^$\\\\|]".toRegex()
val LFRegex = "\n".toRegex()
}
@@ -0,0 +1,18 @@
package io.legato.kazusa.constant
import androidx.annotation.IntDef
@Suppress("ConstPropertyName")
object BookSourceType {
const val default = 0 // 0 文本
const val audio = 1 // 1 音频
const val image = 2 // 2 图片
const val file = 3 // 3 只提供下载服务的网站
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.SOURCE)
@IntDef(default, audio, image, file)
annotation class Type
}
@@ -0,0 +1,73 @@
package io.legato.kazusa.constant
import androidx.annotation.IntDef
/**
* 以二进制位来区分,可能一本书籍包含多个类型,每一位代表一个类型,数值为2的n次方
* 以二进制位来区分,数据库查询更高效, 数值>=8和老版本类型区分开
*/
@Suppress("ConstPropertyName")
object BookType {
/**
* 8 文本
*/
const val text = 0b1000
/**
* 16 更新失败
*/
const val updateError = 0b10000
/**
* 32 音频
*/
const val audio = 0b100000
/**
* 64 图片
*/
const val image = 0b1000000
/**
* 128 只提供下载服务的网站
*/
const val webFile = 0b10000000
/**
* 256 本地
*/
const val local = 0b100000000
/**
* 512 压缩包 表明书籍文件是从压缩包内解压来的
*/
const val archive = 0b1000000000
/**
* 1024 未正式加入到书架的临时阅读书籍
*/
const val notShelf = 0b100_0000_0000
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.SOURCE)
@IntDef(text, updateError, audio, image, webFile, local, archive, notShelf)
annotation class Type
/**
* 所有可以从书源转换的书籍类型
*/
const val allBookType = text or image or audio or webFile
const val allBookTypeLocal = text or image or audio or webFile or local
/**
* 本地书籍书源标志
*/
const val localTag = "loc_book"
/**
* 书源已webDav::开头的书籍,可以从webDav更新或重新下载
*/
const val webDavTag = "webDav::"
}
@@ -0,0 +1,35 @@
package io.legato.kazusa.constant
object EventBus {
const val MEDIA_BUTTON = "mediaButton"
const val RECREATE = "RECREATE"
const val UP_BOOKSHELF = "upBookToc"
const val BOOKSHELF_REFRESH = "bookshelfRefresh"
const val ALOUD_STATE = "aloud_state"
const val TTS_PROGRESS = "ttsStart"
const val AUDIO_DS = "audioDs"
const val READ_ALOUD_DS = "readAloudDs"
const val BATTERY_CHANGED = "batteryChanged"
const val TIME_CHANGED = "timeChanged"
const val UP_CONFIG = "upConfig"
const val AUDIO_SUB_TITLE = "audioSubTitle"
const val AUDIO_STATE = "audioState"
const val AUDIO_PROGRESS = "audioProgress"
const val AUDIO_BUFFER_PROGRESS = "audioBufferProgress"
const val AUDIO_SIZE = "audioSize"
const val AUDIO_SPEED = "audioSpeed"
const val NOTIFY_MAIN = "notifyMain"
const val WEB_SERVICE = "webService"
const val UP_DOWNLOAD = "upDownload"
const val SAVE_CONTENT = "saveContent"
const val CHECK_SOURCE = "checkSource"
const val CHECK_SOURCE_DONE = "checkSourceDone"
const val TIP_COLOR = "tipColor"
const val SOURCE_CHANGED = "sourceChanged"
const val SEARCH_RESULT = "searchResult"
const val UPDATE_READ_ACTION_BAR = "updateReadActionBar"
const val UP_SEEK_BAR = "upSeekBar"
const val READ_ALOUD_PLAY = "readAloudPlay"
const val EXPORT_BOOK = "exportBook"
const val UP_MANGA_CONFIG = "upMangaConfig"
}
@@ -0,0 +1,25 @@
package io.legato.kazusa.constant
@Suppress("ConstPropertyName")
object IntentAction {
const val start = "start"
const val play = "play"
const val playNew = "playNew"
const val stop = "stop"
const val resume = "resume"
const val pause = "pause"
const val addTimer = "addTimer"
const val setTimer = "setTimer"
const val prevParagraph = "prevParagraph"
const val nextParagraph = "nextParagraph"
const val upTtsSpeechRate = "upTtsSpeechRate"
const val upTtsProgress = "upTtsProgress"
const val adjustProgress = "adjustProgress"
const val adjustSpeed = "adjustSpeed"
const val prev = "prev"
const val next = "next"
const val moveTo = "moveTo"
const val init = "init"
const val remove = "remove"
const val stopPlay = "stopPlay"
}
@@ -0,0 +1,19 @@
package io.legato.kazusa.constant
/**
* 通知ID不能重复,统一规划通知ID
*/
@Suppress("ConstPropertyName")
object NotificationId {
const val ReadAloudService = 101
const val AudioPlayService = 102
const val CacheBookService = 103
const val ExportBookService = 104
const val WebService = 105
const val DownloadService = 106
const val CheckSourceService = 107
const val Download = 10000
const val ExportBook = 201
}
@@ -0,0 +1,23 @@
package io.legato.kazusa.constant
import androidx.annotation.IntDef
@Suppress("ConstPropertyName")
object PageAnim {
const val coverPageAnim = 0
const val slidePageAnim = 1
const val simulationPageAnim = 2
const val scrollPageAnim = 3
const val noAnim = 4
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.SOURCE)
@IntDef(coverPageAnim, slidePageAnim, simulationPageAnim, scrollPageAnim, noAnim)
annotation class Anim
}
@@ -0,0 +1,183 @@
package io.legato.kazusa.constant
@Suppress("ConstPropertyName")
object PreferKey {
const val language = "language"
const val fontScale = "fontScale"
const val themeMode = "themeMode"
const val userAgent = "userAgent"
const val showUnread = "showUnread"
const val bookGroupStyle = "bookGroupStyle"
const val useDefaultCover = "useDefaultCover"
const val loadCoverOnlyWifi = "loadCoverOnlyWifi"
const val coverShowName = "coverShowName"
const val coverShowAuthor = "coverShowAuthor"
const val coverShowNameN = "coverShowNameN"
const val coverShowAuthorN = "coverShowAuthorN"
const val remoteServerId = "remoteServerId"
const val hideStatusBar = "hideStatusBar"
const val clickActionTL = "clickActionTopLeft"
const val clickActionTC = "clickActionTopCenter"
const val clickActionTR = "clickActionTopRight"
const val clickActionML = "clickActionMiddleLeft"
const val clickActionMC = "clickActionMiddleCenter"
const val clickActionMR = "clickActionMiddleRight"
const val clickActionBL = "clickActionBottomLeft"
const val clickActionBC = "clickActionBottomCenter"
const val clickActionBR = "clickActionBottomRight"
const val hideNavigationBar = "hideNavigationBar"
const val precisionSearch = "precisionSearch"
const val readAloudByPage = "readAloudByPage"
const val ttsEngine = "appTtsEngine"
const val ttsFollowSys = "ttsFollowSys"
const val ttsSpeechRate = "ttsSpeechRate"
const val prevKeys = "prevKeyCodes"
const val nextKeys = "nextKeyCodes"
const val showDiscovery = "showDiscovery"
const val enableReview = "enableReview"
const val showRss = "showRss"
const val bookshelfLayout = "bookshelfLayout"
const val bookshelfSort = "bookshelfSort"
const val bookExportFileName = "bookExportFileName"
const val bookImportFileName = "bookImportFileName"
const val episodeExportFileName = "episodeExportFileName"
const val recordLog = "recordLog"
const val processText = "process_text"
const val cleanCache = "cleanCache"
const val saveTabPosition = "saveTabPosition"
const val fontFolder = "fontFolder"
const val backupPath = "backupUri"
const val restoreIgnore = "restoreIgnore"
const val threadCount = "threadCount"
const val webPort = "webPort"
const val keepLight = "keep_light"
const val webService = "webService"
const val webDavUrl = "web_dav_url"
const val webDavAccount = "web_dav_account"
const val webDavPassword = "web_dav_password"
const val webDavDir = "webDavDir"
const val enableCustomExport = "enableCustomExport"
const val exportToWebDav = "webDavCacheBackup"
const val exportNoChapterName = "exportNoChapterName"
const val exportType = "exportType"
const val exportPictureFile = "exportPictureFile"
const val changeSourceCheckAuthor = "changeSourceCheckAuthor"
const val changeSourceLoadToc = "changeSourceLoadToc"
const val changeSourceLoadInfo = "changeSourceLoadInfo"
const val changeSourceLoadWordCount = "changeSourceLoadWordCount"
const val chineseConverterType = "chineseConverterType"
const val launcherIcon = "launcherIcon"
const val textSelectAble = "selectText"
const val shareLayout = "shareLayout"
const val comicStyleSelect = "comicStyleSelect"
const val readStyleSelect = "readStyleSelect"
const val systemTypefaces = "system_typefaces"
const val readBodyToLh = "readBodyToLh"
const val textFullJustify = "textFullJustify"
const val textBottomJustify = "textBottomJustify"
const val autoReadSpeed = "autoReadSpeed"
//const val barElevation = "barElevation"
//const val transparentStatusBar = "transparentStatusBar"
//const val immNavigationBar = "immNavigationBar"
const val defaultCover = "defaultCover"
const val defaultCoverDark = "defaultCoverDark"
const val replaceEnableDefault = "replaceEnableDefault"
const val showBrightnessView = "showBrightnessView"
const val autoClearExpired = "autoClearExpired"
const val autoChangeSource = "autoChangeSource"
const val importKeepName = "importKeepName"
const val importKeepGroup = "importKeepGroup"
const val screenOrientation = "screenOrientation"
const val syncBookProgress = "syncBookProgress"
const val syncBookProgressPlus = "syncBookProgressPlus"
const val cronet = "Cronet"
const val antiAlias = "antiAlias"
const val bitmapCacheSize = "bitmapCacheSize"
const val imageRetainNum = "imageRetainNum"
const val preDownloadNum = "preDownloadNum"
const val mangaPreDownloadNum = "mangaPreDownloadNum"
const val mangaAutoPageSpeed = "mangaAutoPageSpeed"
const val mangaFooterConfig = "mangaFooterConfig"
const val disableClickScroll = "disableClickScroll"
const val enableMangaHorizontalScroll = "enableMangaHorizontalScroll"
const val hideMangaTitle = "hideMangaTitle"
const val mangaColorFilter = "mangaColorFilter"
const val autoRefresh = "auto_refresh"
const val defaultToRead = "defaultToRead"
const val exportCharset = "exportCharset"
const val exportUseReplace = "exportUseReplace"
const val useZhLayout = "useZhLayout"
const val brightness = "brightness"
const val nightBrightness = "nightBrightness"
const val expandTextMenu = "expandTextMenu"
const val doublePageHorizontal = "doubleHorizontalPage"
const val readUrlOpenInBrowser = "readUrlInBrowser"
const val defaultBookTreeUri = "defaultBookTreeUri"
const val checkSource = "checkSource"
const val uploadRule = "uploadRule"
const val tocUiUseReplace = "tocUiUseReplace"
const val tocCountWords = "tocCountWords"
const val enableReadRecord = "enableReadRecord"
const val localBookImportSort = "localBookImportSort"
const val customWelcome = "customWelcome"
const val welcomeImage = "welcomeImagePath"
const val welcomeImageDark = "welcomeImagePathDark"
const val welcomeShowText = "welcomeShowText"
const val welcomeShowTextDark = "welcomeShowTextDark"
const val welcomeShowIcon = "welcomeShowIcon"
const val welcomeShowIconDark = "welcomeShowIconDark"
const val pageTouchSlop = "pageTouchSlop"
const val showAddToShelfAlert = "showAddToShelfAlert"
const val ignoreAudioFocus = "ignoreAudioFocus"
const val parallelExportBook = "parallelExportBook"
const val progressBarBehavior = "progressBarBehavior"
const val sourceEditMaxLine = "sourceEditMaxLine"
const val ttsTimer = "ttsTimer"
const val noAnimScrollPage = "noAnimScrollPage"
const val webDavDeviceName = "webDavDeviceName"
const val webServiceWakeLock = "webServiceWakeLock"
const val audioPlayWakeLock = "audioPlayWakeLock"
const val readAloudWakeLock = "readAloudWakeLock"
const val showLastUpdateTime = "showLastUpdateTime"
const val showWaitUpCount = "showWaitUpCount"
const val clearWebViewData = "clearWebViewData"
const val onlyLatestBackup = "onlyLatestBackup"
const val brightnessVwPos = "brightnessVwPos"
const val shrinkDatabase = "shrinkDatabase"
const val batchChangeSourceDelay = "batchChangeSourceDelay"
const val openBookInfoByClickTitle = "openBookInfoByClickTitle"
const val defaultHomePage = "defaultHomePage"
const val showBookshelfFastScroller = "showBookshelfFastScroller"
const val importKeepEnable = "importKeepEnable"
const val previewImageByClick = "previewImageByClick"
const val keyPageOnLongPress = "keyPageOnLongPress"
const val volumeKeyPage = "volumeKeyPage"
const val volumeKeyPageOnPlay = "volumeKeyPageOnPlay"
const val mouseWheelPage = "mouseWheelPage"
const val recordHeapDump = "recordHeapDump"
const val optimizeRender = "optimizeRender"
const val updateToVariant = "updateToVariant"
const val streamReadAloudAudio = "streamReadAloudAudio"
const val pauseReadAloudWhilePhoneCalls = "pauseReadAloudWhilePhoneCalls"
const val readAloudByMediaButton = "readAloudByMediaButton"
const val showMangaUi = "showMangaUi"
const val disableMangaScale = "disableMangaScale"
const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent"
const val cBackground = "colorBackground"
const val cBBackground = "colorBottomBackground"
const val bgImage = "backgroundImage"
const val bgImageBlurring = "backgroundImageBlurring"
const val cNPrimary = "colorPrimaryNight"
const val cNAccent = "colorAccentNight"
const val cNBackground = "colorBackgroundNight"
const val cNBBackground = "colorBottomBackgroundNight"
const val bgImageN = "backgroundImageNight"
const val bgImageNBlurring = "backgroundImageNightBlurring"
const val showReadTitleAddition = "showReadTitleAddition"
const val readBarStyleFollowPage = "readBarStyleFollowPage"
const val contentSelectSpeakMod = "contentReadAloudMod"
}
@@ -0,0 +1,16 @@
package io.legato.kazusa.constant
import androidx.annotation.IntDef
@Suppress("ConstPropertyName")
object SourceType {
const val book = 0
const val rss = 1
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.SOURCE)
@IntDef(book, rss)
annotation class Type
}
@@ -0,0 +1,7 @@
package io.legato.kazusa.constant
object Status {
const val STOP = 0
const val PLAY = 1
const val PAUSE = 3
}
@@ -0,0 +1,5 @@
package io.legato.kazusa.constant
enum class Theme {
Dark, Light, Auto, Transparent, EInk;
}