File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,7 @@ object PreferKey {
|
|||||||
const val prevKeys = "prevKeyCodes"
|
const val prevKeys = "prevKeyCodes"
|
||||||
const val nextKeys = "nextKeyCodes"
|
const val nextKeys = "nextKeyCodes"
|
||||||
const val showDiscovery = "showDiscovery"
|
const val showDiscovery = "showDiscovery"
|
||||||
|
const val enableReview = "enableReview"
|
||||||
const val showRss = "showRss"
|
const val showRss = "showRss"
|
||||||
const val bookshelfLayout = "bookshelfLayout"
|
const val bookshelfLayout = "bookshelfLayout"
|
||||||
const val bookshelfSort = "bookshelfSort"
|
const val bookshelfSort = "bookshelfSort"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ val appDb by lazy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
version = 52,
|
version = 53,
|
||||||
exportSchema = true,
|
exportSchema = true,
|
||||||
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
|
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
|
||||||
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
|
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
|
||||||
@@ -36,7 +36,8 @@ val appDb by lazy {
|
|||||||
AutoMigration(from = 48, to = 49),
|
AutoMigration(from = 48, to = 49),
|
||||||
AutoMigration(from = 49, to = 50),
|
AutoMigration(from = 49, to = 50),
|
||||||
AutoMigration(from = 50, to = 51),
|
AutoMigration(from = 50, to = 51),
|
||||||
AutoMigration(from = 51, to = 52)
|
AutoMigration(from = 51, to = 52),
|
||||||
|
AutoMigration(from = 52, to = 53)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ interface BookSourceDao {
|
|||||||
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
|
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
|
||||||
fun flowExplore(): Flow<List<BookSource>>
|
fun flowExplore(): Flow<List<BookSource>>
|
||||||
|
|
||||||
|
// @Query("select * from book_sources where enabledReview = 1 order by customOrder asc")
|
||||||
|
// fun flowReview(): Flow<List<BookSource>>
|
||||||
|
|
||||||
@Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
|
@Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
|
||||||
fun flowLogin(): Flow<List<BookSource>>
|
fun flowLogin(): Flow<List<BookSource>>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.legado.app.data.entities
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.room.ColumnInfo
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
class BookChapterReview(
|
||||||
|
@ColumnInfo(defaultValue = "0")
|
||||||
|
var bookId: Long = 0,
|
||||||
|
var chapterId: Long = 0,
|
||||||
|
var summaryUrl: String = "",
|
||||||
|
): Parcelable {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -37,7 +37,9 @@ data class BookSource(
|
|||||||
// 是否启用
|
// 是否启用
|
||||||
var enabled: Boolean = true,
|
var enabled: Boolean = true,
|
||||||
// 启用发现
|
// 启用发现
|
||||||
var enabledExplore: Boolean = true,
|
var enabledExplore: Boolean = false,
|
||||||
|
// 启用段评
|
||||||
|
var enabledReview: Boolean? = false,
|
||||||
// 启用okhttp CookieJAr 自动保存每次请求的cookie
|
// 启用okhttp CookieJAr 自动保存每次请求的cookie
|
||||||
@ColumnInfo(defaultValue = "0")
|
@ColumnInfo(defaultValue = "0")
|
||||||
override var enabledCookieJar: Boolean? = false,
|
override var enabledCookieJar: Boolean? = false,
|
||||||
@@ -74,7 +76,9 @@ data class BookSource(
|
|||||||
// 目录页规则
|
// 目录页规则
|
||||||
var ruleToc: TocRule? = null,
|
var ruleToc: TocRule? = null,
|
||||||
// 正文页规则
|
// 正文页规则
|
||||||
var ruleContent: ContentRule? = null
|
var ruleContent: ContentRule? = null,
|
||||||
|
// 段评规则
|
||||||
|
var ruleReview: ReviewRule? = null
|
||||||
) : Parcelable, BaseSource {
|
) : Parcelable, BaseSource {
|
||||||
|
|
||||||
override fun getTag(): String {
|
override fun getTag(): String {
|
||||||
@@ -170,6 +174,13 @@ data class BookSource(
|
|||||||
return rule
|
return rule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getReviewRule(): ReviewRule {
|
||||||
|
ruleReview?.let { return it }
|
||||||
|
val rule = ReviewRule()
|
||||||
|
ruleReview = rule
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
|
||||||
fun getDisPlayNameGroup(): String {
|
fun getDisPlayNameGroup(): String {
|
||||||
return if (bookSourceGroup.isNullOrBlank()) {
|
return if (bookSourceGroup.isNullOrBlank()) {
|
||||||
bookSourceName
|
bookSourceName
|
||||||
@@ -303,5 +314,13 @@ data class BookSource(
|
|||||||
fun stringToContentRule(json: String?) =
|
fun stringToContentRule(json: String?) =
|
||||||
GSON.fromJsonObject<ContentRule>(json).getOrNull()
|
GSON.fromJsonObject<ContentRule>(json).getOrNull()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun stringToReviewRule(json: String?) =
|
||||||
|
GSON.fromJsonObject<ReviewRule>(json).getOrNull()
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun reviewRuleToString(reviewRule: ReviewRule?): String =
|
||||||
|
GSON.toJson(reviewRule)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package io.legado.app.data.entities.rule
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class ReviewRule(
|
||||||
|
var reviewUrl: String? = null, // 段评URL
|
||||||
|
var avatarRule: String? = null, // 段评发布者头像
|
||||||
|
var contentRule: String? = null, // 段评内容
|
||||||
|
var postTimeRule: String? = null, // 段评发布时间
|
||||||
|
var reviewQuoteUrl: String? = null, // 获取段评回复URL
|
||||||
|
|
||||||
|
// 这些功能将在以上功能完成以后实现
|
||||||
|
var voteUpUrl: String? = null, // 点赞URL
|
||||||
|
var voteDownUrl: String? = null, // 点踩URL
|
||||||
|
var postReviewUrl: String? = null, // 发送回复URL
|
||||||
|
var postQuoteUrl: String? = null, // 发送回复段评URL
|
||||||
|
var deleteUrl: String? = null, // 删除段评URL
|
||||||
|
): Parcelable
|
||||||
@@ -151,6 +151,7 @@ object SourceAnalyzer {
|
|||||||
source.enabled = sourceAny.enabled
|
source.enabled = sourceAny.enabled
|
||||||
source.enabledExplore = sourceAny.enabledExplore
|
source.enabledExplore = sourceAny.enabledExplore
|
||||||
source.enabledCookieJar = sourceAny.enabledCookieJar
|
source.enabledCookieJar = sourceAny.enabledCookieJar
|
||||||
|
source.enabledReview = sourceAny.enabledReview
|
||||||
source.concurrentRate = sourceAny.concurrentRate
|
source.concurrentRate = sourceAny.concurrentRate
|
||||||
source.header = sourceAny.header
|
source.header = sourceAny.header
|
||||||
source.loginUrl = when (sourceAny.loginUrl) {
|
source.loginUrl = when (sourceAny.loginUrl) {
|
||||||
@@ -206,6 +207,13 @@ object SourceAnalyzer {
|
|||||||
GSON.fromJsonObject<ContentRule>(GSON.toJson(sourceAny.ruleContent))
|
GSON.fromJsonObject<ContentRule>(GSON.toJson(sourceAny.ruleContent))
|
||||||
.getOrNull()
|
.getOrNull()
|
||||||
}
|
}
|
||||||
|
source.ruleReview = if (sourceAny.ruleReview is String) {
|
||||||
|
GSON.fromJsonObject<ReviewRule>(sourceAny.ruleReview.toString())
|
||||||
|
.getOrNull()
|
||||||
|
} else {
|
||||||
|
GSON.fromJsonObject<ReviewRule>(GSON.toJson(sourceAny.ruleReview))
|
||||||
|
.getOrNull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
source
|
source
|
||||||
}
|
}
|
||||||
@@ -221,6 +229,7 @@ object SourceAnalyzer {
|
|||||||
var customOrder: Int = 0, // 手动排序编号
|
var customOrder: Int = 0, // 手动排序编号
|
||||||
var enabled: Boolean = true, // 是否启用
|
var enabled: Boolean = true, // 是否启用
|
||||||
var enabledExplore: Boolean = true, // 启用发现
|
var enabledExplore: Boolean = true, // 启用发现
|
||||||
|
var enabledReview: Boolean = false, // 启用段评
|
||||||
var enabledCookieJar: Boolean = false, // 启用CookieJar
|
var enabledCookieJar: Boolean = false, // 启用CookieJar
|
||||||
var concurrentRate: String? = null, // 并发率
|
var concurrentRate: String? = null, // 并发率
|
||||||
var header: String? = null, // 请求头
|
var header: String? = null, // 请求头
|
||||||
@@ -238,7 +247,8 @@ object SourceAnalyzer {
|
|||||||
var ruleSearch: Any? = null, // 搜索规则
|
var ruleSearch: Any? = null, // 搜索规则
|
||||||
var ruleBookInfo: Any? = null, // 书籍信息页规则
|
var ruleBookInfo: Any? = null, // 书籍信息页规则
|
||||||
var ruleToc: Any? = null, // 目录页规则
|
var ruleToc: Any? = null, // 目录页规则
|
||||||
var ruleContent: Any? = null // 正文页规则
|
var ruleContent: Any? = null, // 正文页规则
|
||||||
|
var ruleReview: Any? = null // 段评规则
|
||||||
)
|
)
|
||||||
|
|
||||||
// default规则适配
|
// default规则适配
|
||||||
|
|||||||
@@ -154,6 +154,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
|||||||
val autoRefreshBook: Boolean
|
val autoRefreshBook: Boolean
|
||||||
get() = appCtx.getPrefBoolean(PreferKey.autoRefresh)
|
get() = appCtx.getPrefBoolean(PreferKey.autoRefresh)
|
||||||
|
|
||||||
|
var enableReview: Boolean
|
||||||
|
get() = appCtx.getPrefBoolean(PreferKey.enableReview, false)
|
||||||
|
set(value) {
|
||||||
|
appCtx.putPrefBoolean(PreferKey.enableReview, value)
|
||||||
|
}
|
||||||
|
|
||||||
var threadCount: Int
|
var threadCount: Int
|
||||||
get() = appCtx.getPrefInt(PreferKey.threadCount, 16)
|
get() = appCtx.getPrefInt(PreferKey.threadCount, 16)
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ object ReadBookConfig {
|
|||||||
var letterSpacing: Float = 0.1f,//字间距
|
var letterSpacing: Float = 0.1f,//字间距
|
||||||
var lineSpacingExtra: Int = 12,//行间距
|
var lineSpacingExtra: Int = 12,//行间距
|
||||||
var paragraphSpacing: Int = 2,//段距
|
var paragraphSpacing: Int = 2,//段距
|
||||||
var titleMode: Int = 0,//标题居中
|
var titleMode: Int = 0,//标题位置 0:居左 1:居中 2:隐藏
|
||||||
var titleSize: Int = 0,
|
var titleSize: Int = 0,
|
||||||
var titleTopSpacing: Int = 0,
|
var titleTopSpacing: Int = 0,
|
||||||
var titleBottomSpacing: Int = 0,
|
var titleBottomSpacing: Int = 0,
|
||||||
|
|||||||
@@ -300,6 +300,13 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取段评
|
||||||
|
*/
|
||||||
|
fun getReview() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 精准搜索
|
* 精准搜索
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
else -> when (item.itemId) {
|
else -> when (item.itemId) {
|
||||||
R.id.menu_enable_replace -> item.isChecked = book.getUseReplaceRule()
|
R.id.menu_enable_replace -> item.isChecked = book.getUseReplaceRule()
|
||||||
R.id.menu_re_segment -> item.isChecked = book.getReSegment()
|
R.id.menu_re_segment -> item.isChecked = book.getReSegment()
|
||||||
|
R.id.menu_enable_review -> item.isChecked = AppConfig.enableReview
|
||||||
R.id.menu_reverse_content -> item.isVisible = onLine
|
R.id.menu_reverse_content -> item.isVisible = onLine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,6 +356,11 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
menu?.findItem(R.id.menu_re_segment)?.isChecked = it.getReSegment()
|
menu?.findItem(R.id.menu_re_segment)?.isChecked = it.getReSegment()
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
}
|
}
|
||||||
|
R.id.menu_enable_review -> {
|
||||||
|
AppConfig.enableReview = !AppConfig.enableReview
|
||||||
|
menu?.findItem(R.id.menu_enable_review)?.isChecked = AppConfig.enableReview
|
||||||
|
ReadBook.loadContent(false)
|
||||||
|
}
|
||||||
R.id.menu_page_anim -> showPageAnimConfig {
|
R.id.menu_page_anim -> showPageAnimConfig {
|
||||||
binding.readView.upPageAnim()
|
binding.readView.upPageAnim()
|
||||||
ReadBook.loadContent(false)
|
ReadBook.loadContent(false)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import android.content.Context
|
|||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.RectF
|
import android.graphics.RectF
|
||||||
|
import android.text.StaticLayout
|
||||||
|
import android.text.TextPaint
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
@@ -14,10 +16,7 @@ import io.legado.app.help.config.AppConfig
|
|||||||
import io.legado.app.help.config.ReadBookConfig
|
import io.legado.app.help.config.ReadBookConfig
|
||||||
import io.legado.app.lib.theme.accentColor
|
import io.legado.app.lib.theme.accentColor
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.ui.book.read.page.entities.TextColumn
|
import io.legado.app.ui.book.read.page.entities.*
|
||||||
import io.legado.app.ui.book.read.page.entities.TextLine
|
|
||||||
import io.legado.app.ui.book.read.page.entities.TextPage
|
|
||||||
import io.legado.app.ui.book.read.page.entities.TextPos
|
|
||||||
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
import io.legado.app.ui.book.read.page.provider.ChapterProvider
|
||||||
import io.legado.app.ui.book.read.page.provider.ImageProvider
|
import io.legado.app.ui.book.read.page.provider.ImageProvider
|
||||||
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
||||||
@@ -159,16 +158,91 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
ChapterProvider.contentPaint
|
ChapterProvider.contentPaint
|
||||||
}
|
}
|
||||||
val textColor = if (textLine.isReadAloud) context.accentColor else ReadBookConfig.textColor
|
val textColor = if (textLine.isReadAloud) context.accentColor else ReadBookConfig.textColor
|
||||||
|
val linePaint = Paint()
|
||||||
|
linePaint.strokeWidth = textPaint.textSize / 21
|
||||||
|
linePaint.color = textColor
|
||||||
|
val reviewCountPaint = TextPaint()
|
||||||
|
reviewCountPaint.textSize = textPaint.textSize * 0.6F
|
||||||
|
reviewCountPaint.color = textColor
|
||||||
textLine.textChars.forEach {
|
textLine.textChars.forEach {
|
||||||
if (it.style == 1) {
|
when (it.style) {
|
||||||
drawImage(canvas, textPage, textLine, it, lineTop, lineBottom)
|
0 -> {
|
||||||
} else {
|
|
||||||
textPaint.color = textColor
|
textPaint.color = textColor
|
||||||
if (it.isSearchResult) {
|
if (it.isSearchResult) {
|
||||||
textPaint.color = context.accentColor
|
textPaint.color = context.accentColor
|
||||||
}
|
}
|
||||||
canvas.drawText(it.charData, it.start, lineBase, textPaint)
|
canvas.drawText(it.charData, it.start, lineBase, textPaint)
|
||||||
}
|
}
|
||||||
|
1 -> drawImage(canvas, textPage, textLine, it, lineTop, lineBottom)
|
||||||
|
2 -> {
|
||||||
|
if (textLine.reviewCount <= 0) return@forEach
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start,
|
||||||
|
lineBase - textPaint.textSize * 2 / 5,
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize / 4,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start,
|
||||||
|
lineBase - textPaint.textSize * 0.38F,
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize * 0.55F,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize / 4,
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize * 0.55F,
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize * 0.8F,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase,
|
||||||
|
it.start + textPaint.textSize * 1.6F,
|
||||||
|
lineBase,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start + textPaint.textSize / 6,
|
||||||
|
lineBase - textPaint.textSize * 0.8F,
|
||||||
|
it.start + textPaint.textSize * 1.6F,
|
||||||
|
lineBase - textPaint.textSize * 0.8F,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
canvas.drawLine(
|
||||||
|
it.start + textPaint.textSize * 1.6F,
|
||||||
|
lineBase - textPaint.textSize * 0.8F,
|
||||||
|
it.start + textPaint.textSize * 1.6F,
|
||||||
|
lineBase,
|
||||||
|
linePaint
|
||||||
|
)
|
||||||
|
if (textLine.reviewCount < 100) canvas.drawText(
|
||||||
|
textLine.reviewCount.toString(),
|
||||||
|
it.start + textPaint.textSize * 0.87F -
|
||||||
|
StaticLayout.getDesiredWidth(
|
||||||
|
textLine.reviewCount.toString(),
|
||||||
|
reviewCountPaint
|
||||||
|
) / 2,
|
||||||
|
lineBase - textPaint.textSize / 6,
|
||||||
|
reviewCountPaint
|
||||||
|
)
|
||||||
|
else canvas.drawText(
|
||||||
|
"99+",
|
||||||
|
it.start + textPaint.textSize * 0.35F,
|
||||||
|
lineBase - textPaint.textSize / 6,
|
||||||
|
reviewCountPaint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
if (it.selected) {
|
if (it.selected) {
|
||||||
canvas.drawRect(it.start, lineTop, it.end, lineBottom, selectedPaint)
|
canvas.drawRect(it.start, lineTop, it.end, lineBottom, selectedPaint)
|
||||||
}
|
}
|
||||||
@@ -283,12 +357,13 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
y: Float,
|
y: Float,
|
||||||
select: (textPos: TextPos) -> Unit,
|
select: (textPos: TextPos) -> Unit,
|
||||||
) {
|
) {
|
||||||
touch(x, y) { _, textPos, _, _, textChar ->
|
touch(x, y) { _, textPos, _, _, textColumn ->
|
||||||
if (textChar.style == 1) {
|
if (textColumn.style == 2) return@touch
|
||||||
callBack.onImageLongPress(x, y, textChar.charData)
|
if (textColumn.style == 1) {
|
||||||
|
callBack.onImageLongPress(x, y, textColumn.charData)
|
||||||
} else {
|
} else {
|
||||||
if (!selectAble) return@touch
|
if (!selectAble) return@touch
|
||||||
textChar.selected = true
|
textColumn.selected = true
|
||||||
invalidate()
|
invalidate()
|
||||||
select(textPos)
|
select(textPos)
|
||||||
}
|
}
|
||||||
@@ -300,10 +375,14 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
* @return true:已处理, false:未处理
|
* @return true:已处理, false:未处理
|
||||||
*/
|
*/
|
||||||
fun click(x: Float, y: Float): Boolean {
|
fun click(x: Float, y: Float): Boolean {
|
||||||
touch(x, y) { _, textPos, textPage, textLine, textChar ->
|
var handled = false
|
||||||
|
touch(x, y) { _, textPos, textPage, textLine, textColumn ->
|
||||||
|
if (textColumn.style == 2) {
|
||||||
|
context.toastOnUi("Button Pressed!")
|
||||||
|
handled = true
|
||||||
}
|
}
|
||||||
return false
|
}
|
||||||
|
return handled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -314,8 +393,9 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
y: Float,
|
y: Float,
|
||||||
select: (textPos: TextPos) -> Unit,
|
select: (textPos: TextPos) -> Unit,
|
||||||
) {
|
) {
|
||||||
touch(x, y) { _, textPos, _, _, textChar ->
|
touch(x, y) { _, textPos, _, _, textColumn ->
|
||||||
textChar.selected = true
|
if (textColumn.style == 2) return@touch
|
||||||
|
textColumn.selected = true
|
||||||
invalidate()
|
invalidate()
|
||||||
select(textPos)
|
select(textPos)
|
||||||
}
|
}
|
||||||
@@ -437,6 +517,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at
|
|||||||
textPos.lineIndex = lineIndex
|
textPos.lineIndex = lineIndex
|
||||||
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
|
for ((charIndex, textChar) in textLine.textChars.withIndex()) {
|
||||||
textPos.charIndex = charIndex
|
textPos.charIndex = charIndex
|
||||||
|
if (textChar.style == 2) continue
|
||||||
textChar.selected =
|
textChar.selected =
|
||||||
textPos.compare(selectStart) >= 0 && textPos.compare(selectEnd) <= 0
|
textPos.compare(selectStart) >= 0 && textPos.compare(selectEnd) <= 0
|
||||||
textChar.isSearchResult = textChar.selected && callBack.isSelectingSearchResult
|
textChar.isSearchResult = textChar.selected && callBack.isSelectingSearchResult
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import io.legado.app.ui.book.read.page.provider.TextPageFactory
|
|||||||
import io.legado.app.utils.activity
|
import io.legado.app.utils.activity
|
||||||
import io.legado.app.utils.invisible
|
import io.legado.app.utils.invisible
|
||||||
import io.legado.app.utils.screenshot
|
import io.legado.app.utils.screenshot
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
import java.text.BreakIterator
|
import java.text.BreakIterator
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import io.legado.app.utils.textHeight
|
|||||||
data class TextLine(
|
data class TextLine(
|
||||||
var text: String = "",
|
var text: String = "",
|
||||||
val textChars: ArrayList<TextColumn> = arrayListOf(),
|
val textChars: ArrayList<TextColumn> = arrayListOf(),
|
||||||
|
val reviewCount: Int = 0,
|
||||||
var lineTop: Float = 0f,
|
var lineTop: Float = 0f,
|
||||||
var lineBase: Float = 0f,
|
var lineBase: Float = 0f,
|
||||||
var lineBottom: Float = 0f,
|
var lineBottom: Float = 0f,
|
||||||
|
|||||||
@@ -114,7 +114,12 @@ data class TextPage(
|
|||||||
val cw = StaticLayout.getDesiredWidth(char, ChapterProvider.contentPaint)
|
val cw = StaticLayout.getDesiredWidth(char, ChapterProvider.contentPaint)
|
||||||
val x1 = x + cw
|
val x1 = x + cw
|
||||||
textLine.textChars.add(
|
textLine.textChars.add(
|
||||||
TextColumn(char, start = x, end = x1)
|
TextColumn(
|
||||||
|
char,
|
||||||
|
start = x,
|
||||||
|
end = x1,
|
||||||
|
style = if (textLine.text.length - 1 == index && char == "\uD83D\uDCAC") 2 else 0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
x = x1
|
x = x1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,13 @@ object ChapterProvider {
|
|||||||
if (ReadBookConfig.titleMode != 2) {
|
if (ReadBookConfig.titleMode != 2) {
|
||||||
displayTitle.splitNotBlank("\n").forEach { text ->
|
displayTitle.splitNotBlank("\n").forEach { text ->
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book, absStartX, durY, text, textPages, stringBuilder, titlePaint,
|
book,
|
||||||
|
absStartX,
|
||||||
|
durY,
|
||||||
|
if (AppConfig.enableReview) text + "\ud83d\udcac" else text,
|
||||||
|
textPages,
|
||||||
|
stringBuilder,
|
||||||
|
titlePaint,
|
||||||
isTitle = true,
|
isTitle = true,
|
||||||
isTitleWithNoContent = contents.isEmpty(),
|
isTitleWithNoContent = contents.isEmpty(),
|
||||||
isVolumeTitle = bookChapter.isVolume
|
isVolumeTitle = bookChapter.isVolume
|
||||||
@@ -171,7 +177,13 @@ object ChapterProvider {
|
|||||||
val text = content.substring(start, content.length)
|
val text = content.substring(start, content.length)
|
||||||
if (text.isNotBlank()) {
|
if (text.isNotBlank()) {
|
||||||
setTypeText(
|
setTypeText(
|
||||||
book, absStartX, durY, text, textPages, stringBuilder, contentPaint
|
book,
|
||||||
|
absStartX,
|
||||||
|
durY,
|
||||||
|
if (AppConfig.enableReview) text + "\ud83d\udcac" else text,
|
||||||
|
textPages,
|
||||||
|
stringBuilder,
|
||||||
|
contentPaint
|
||||||
).let {
|
).let {
|
||||||
absStartX = it.first
|
absStartX = it.first
|
||||||
durY = it.second
|
durY = it.second
|
||||||
@@ -276,9 +288,8 @@ object ChapterProvider {
|
|||||||
srcList: LinkedList<String>? = null
|
srcList: LinkedList<String>? = null
|
||||||
): Pair<Int, Float> {
|
): Pair<Int, Float> {
|
||||||
var absStartX = x
|
var absStartX = x
|
||||||
val layout = if (ReadBookConfig.useZhLayout) {
|
val layout = if (ReadBookConfig.useZhLayout) ZhLayout(text, textPaint, visibleWidth)
|
||||||
ZhLayout(text, textPaint, visibleWidth)
|
else StaticLayout(
|
||||||
} else StaticLayout(
|
|
||||||
text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true
|
text, textPaint, visibleWidth, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true
|
||||||
)
|
)
|
||||||
var durY = when {
|
var durY = when {
|
||||||
@@ -398,10 +409,14 @@ object ChapterProvider {
|
|||||||
}
|
}
|
||||||
val bodyIndent = ReadBookConfig.paragraphIndent
|
val bodyIndent = ReadBookConfig.paragraphIndent
|
||||||
val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length
|
val icw = StaticLayout.getDesiredWidth(bodyIndent, textPaint) / bodyIndent.length
|
||||||
bodyIndent.toStringArray().forEach { char ->
|
for (char in bodyIndent.toStringArray()) {
|
||||||
val x1 = x + icw
|
val x1 = x + icw
|
||||||
textLine.textChars.add(
|
textLine.textChars.add(
|
||||||
TextColumn(charData = char, start = absStartX + x, end = absStartX + x1)
|
TextColumn(
|
||||||
|
charData = char,
|
||||||
|
start = absStartX + x,
|
||||||
|
end = absStartX + x1
|
||||||
|
)
|
||||||
)
|
)
|
||||||
x = x1
|
x = x1
|
||||||
}
|
}
|
||||||
@@ -436,7 +451,7 @@ object ChapterProvider {
|
|||||||
words.forEachIndexed { index, char ->
|
words.forEachIndexed { index, char ->
|
||||||
val cw = StaticLayout.getDesiredWidth(char, textPaint)
|
val cw = StaticLayout.getDesiredWidth(char, textPaint)
|
||||||
val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw)
|
val x1 = if (index != words.lastIndex) (x + cw + d) else (x + cw)
|
||||||
addCharToLine(book, absStartX, textLine, char, x, x1, srcList)
|
addCharToLine(book, absStartX, textLine, char, x, x1, index + 1 == words.size, srcList)
|
||||||
x = x1
|
x = x1
|
||||||
}
|
}
|
||||||
exceed(absStartX, textLine, words)
|
exceed(absStartX, textLine, words)
|
||||||
@@ -455,10 +470,10 @@ object ChapterProvider {
|
|||||||
srcList: LinkedList<String>?
|
srcList: LinkedList<String>?
|
||||||
) {
|
) {
|
||||||
var x = startX
|
var x = startX
|
||||||
words.forEach { char ->
|
words.forEachIndexed { index, char ->
|
||||||
val cw = StaticLayout.getDesiredWidth(char, textPaint)
|
val cw = StaticLayout.getDesiredWidth(char, textPaint)
|
||||||
val x1 = x + cw
|
val x1 = x + cw
|
||||||
addCharToLine(book, absStartX, textLine, char, x, x1, srcList)
|
addCharToLine(book, absStartX, textLine, char, x, x1, index + 1 == words.size, srcList)
|
||||||
x = x1
|
x = x1
|
||||||
}
|
}
|
||||||
exceed(absStartX, textLine, words)
|
exceed(absStartX, textLine, words)
|
||||||
@@ -474,6 +489,7 @@ object ChapterProvider {
|
|||||||
char: String,
|
char: String,
|
||||||
xStart: Float,
|
xStart: Float,
|
||||||
xEnd: Float,
|
xEnd: Float,
|
||||||
|
isLineEnd: Boolean,
|
||||||
srcList: LinkedList<String>?
|
srcList: LinkedList<String>?
|
||||||
) {
|
) {
|
||||||
if (srcList != null && char == srcReplaceChar) {
|
if (srcList != null && char == srcReplaceChar) {
|
||||||
@@ -492,7 +508,8 @@ object ChapterProvider {
|
|||||||
TextColumn(
|
TextColumn(
|
||||||
charData = char,
|
charData = char,
|
||||||
start = absStartX + xStart,
|
start = absStartX + xStart,
|
||||||
end = absStartX + xEnd
|
end = absStartX + xEnd,
|
||||||
|
style = if (isLineEnd && char == "\uD83D\uDCAC") 2 else 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,11 @@ class BookSourceEditActivity :
|
|||||||
private val adapter by lazy { BookSourceEditAdapter() }
|
private val adapter by lazy { BookSourceEditAdapter() }
|
||||||
private val sourceEntities: ArrayList<EditEntity> = ArrayList()
|
private val sourceEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val searchEntities: ArrayList<EditEntity> = ArrayList()
|
private val searchEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val findEntities: ArrayList<EditEntity> = ArrayList()
|
private val exploreEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val infoEntities: ArrayList<EditEntity> = ArrayList()
|
private val infoEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val tocEntities: ArrayList<EditEntity> = ArrayList()
|
private val tocEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val contentEntities: ArrayList<EditEntity> = ArrayList()
|
private val contentEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
|
private val reviewEntities: ArrayList<EditEntity> = ArrayList()
|
||||||
private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
|
private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
|
||||||
it ?: return@registerForActivityResult
|
it ?: return@registerForActivityResult
|
||||||
viewModel.importSource(it) { source ->
|
viewModel.importSource(it) { source ->
|
||||||
@@ -180,10 +181,11 @@ class BookSourceEditActivity :
|
|||||||
private fun setEditEntities(tabPosition: Int?) {
|
private fun setEditEntities(tabPosition: Int?) {
|
||||||
when (tabPosition) {
|
when (tabPosition) {
|
||||||
1 -> adapter.editEntities = searchEntities
|
1 -> adapter.editEntities = searchEntities
|
||||||
2 -> adapter.editEntities = findEntities
|
2 -> adapter.editEntities = exploreEntities
|
||||||
3 -> adapter.editEntities = infoEntities
|
3 -> adapter.editEntities = infoEntities
|
||||||
4 -> adapter.editEntities = tocEntities
|
4 -> adapter.editEntities = tocEntities
|
||||||
5 -> adapter.editEntities = contentEntities
|
5 -> adapter.editEntities = contentEntities
|
||||||
|
6 -> adapter.editEntities = reviewEntities
|
||||||
else -> adapter.editEntities = sourceEntities
|
else -> adapter.editEntities = sourceEntities
|
||||||
}
|
}
|
||||||
binding.recyclerView.scrollToPosition(0)
|
binding.recyclerView.scrollToPosition(0)
|
||||||
@@ -192,8 +194,9 @@ class BookSourceEditActivity :
|
|||||||
private fun upSourceView(source: BookSource? = viewModel.bookSource) {
|
private fun upSourceView(source: BookSource? = viewModel.bookSource) {
|
||||||
source?.let {
|
source?.let {
|
||||||
binding.cbIsEnable.isChecked = it.enabled
|
binding.cbIsEnable.isChecked = it.enabled
|
||||||
binding.cbIsEnableFind.isChecked = it.enabledExplore
|
binding.cbIsEnableExplore.isChecked = it.enabledExplore
|
||||||
binding.cbIsEnableCookie.isChecked = it.enabledCookieJar ?: false
|
binding.cbIsEnableCookie.isChecked = it.enabledCookieJar ?: false
|
||||||
|
binding.cbIsEnableReview.isChecked = it.enabledReview ?: false
|
||||||
binding.spType.setSelection(
|
binding.spType.setSelection(
|
||||||
when (it.bookSourceType) {
|
when (it.bookSourceType) {
|
||||||
BookType.file -> 3
|
BookType.file -> 3
|
||||||
@@ -236,8 +239,8 @@ class BookSourceEditActivity :
|
|||||||
}
|
}
|
||||||
// 发现
|
// 发现
|
||||||
val er = source?.getExploreRule()
|
val er = source?.getExploreRule()
|
||||||
findEntities.clear()
|
exploreEntities.clear()
|
||||||
findEntities.apply {
|
exploreEntities.apply {
|
||||||
add(EditEntity("exploreUrl", source?.exploreUrl, R.string.r_find_url))
|
add(EditEntity("exploreUrl", source?.exploreUrl, R.string.r_find_url))
|
||||||
add(EditEntity("bookList", er?.bookList, R.string.r_book_list))
|
add(EditEntity("bookList", er?.bookList, R.string.r_book_list))
|
||||||
add(EditEntity("name", er?.name, R.string.r_book_name))
|
add(EditEntity("name", er?.name, R.string.r_book_name))
|
||||||
@@ -291,6 +294,21 @@ class BookSourceEditActivity :
|
|||||||
add(EditEntity("imageStyle", cr?.imageStyle, R.string.rule_image_style))
|
add(EditEntity("imageStyle", cr?.imageStyle, R.string.rule_image_style))
|
||||||
add(EditEntity("payAction", cr?.payAction, R.string.rule_pay_action))
|
add(EditEntity("payAction", cr?.payAction, R.string.rule_pay_action))
|
||||||
}
|
}
|
||||||
|
// 段评
|
||||||
|
val rr = source?.getReviewRule()
|
||||||
|
reviewEntities.clear()
|
||||||
|
reviewEntities.apply {
|
||||||
|
add(EditEntity("reviewUrl", rr?.reviewUrl, R.string.rule_review_url))
|
||||||
|
add(EditEntity("avatarRule", rr?.avatarRule, R.string.rule_avatar))
|
||||||
|
add(EditEntity("contentRule", rr?.contentRule, R.string.rule_review_content))
|
||||||
|
add(EditEntity("postTimeRule", rr?.postTimeRule, R.string.rule_post_time))
|
||||||
|
add(EditEntity("reviewQuoteUrl", rr?.reviewQuoteUrl, R.string.rule_review_quote))
|
||||||
|
add(EditEntity("voteUpUrl", rr?.voteUpUrl, R.string.review_vote_up))
|
||||||
|
add(EditEntity("voteDownUrl", rr?.voteDownUrl, R.string.review_vote_down))
|
||||||
|
add(EditEntity("postReviewUrl", rr?.postReviewUrl, R.string.post_review_url))
|
||||||
|
add(EditEntity("postQuoteUrl", rr?.postQuoteUrl, R.string.post_quote_url))
|
||||||
|
add(EditEntity("deleteUrl", rr?.deleteUrl, R.string.delete_review_url))
|
||||||
|
}
|
||||||
binding.tabLayout.selectTab(binding.tabLayout.getTabAt(0))
|
binding.tabLayout.selectTab(binding.tabLayout.getTabAt(0))
|
||||||
setEditEntities(0)
|
setEditEntities(0)
|
||||||
}
|
}
|
||||||
@@ -298,8 +316,9 @@ class BookSourceEditActivity :
|
|||||||
private fun getSource(): BookSource {
|
private fun getSource(): BookSource {
|
||||||
val source = viewModel.bookSource?.copy() ?: BookSource()
|
val source = viewModel.bookSource?.copy() ?: BookSource()
|
||||||
source.enabled = binding.cbIsEnable.isChecked
|
source.enabled = binding.cbIsEnable.isChecked
|
||||||
source.enabledExplore = binding.cbIsEnableFind.isChecked
|
source.enabledExplore = binding.cbIsEnableExplore.isChecked
|
||||||
source.enabledCookieJar = binding.cbIsEnableCookie.isChecked
|
source.enabledCookieJar = binding.cbIsEnableCookie.isChecked
|
||||||
|
source.enabledReview = binding.cbIsEnableReview.isChecked
|
||||||
source.bookSourceType = when (binding.spType.selectedItemPosition) {
|
source.bookSourceType = when (binding.spType.selectedItemPosition) {
|
||||||
3 -> BookType.file
|
3 -> BookType.file
|
||||||
2 -> BookType.image
|
2 -> BookType.image
|
||||||
@@ -311,6 +330,7 @@ class BookSourceEditActivity :
|
|||||||
val bookInfoRule = BookInfoRule()
|
val bookInfoRule = BookInfoRule()
|
||||||
val tocRule = TocRule()
|
val tocRule = TocRule()
|
||||||
val contentRule = ContentRule()
|
val contentRule = ContentRule()
|
||||||
|
val reviewRule = ReviewRule()
|
||||||
sourceEntities.forEach {
|
sourceEntities.forEach {
|
||||||
when (it.key) {
|
when (it.key) {
|
||||||
"bookSourceUrl" -> source.bookSourceUrl = it.value ?: ""
|
"bookSourceUrl" -> source.bookSourceUrl = it.value ?: ""
|
||||||
@@ -351,7 +371,7 @@ class BookSourceEditActivity :
|
|||||||
viewModel.ruleComplete(it.value, searchRule.bookList, 2)
|
viewModel.ruleComplete(it.value, searchRule.bookList, 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
findEntities.forEach {
|
exploreEntities.forEach {
|
||||||
when (it.key) {
|
when (it.key) {
|
||||||
"exploreUrl" -> source.exploreUrl = it.value
|
"exploreUrl" -> source.exploreUrl = it.value
|
||||||
"bookList" -> exploreRule.bookList = it.value
|
"bookList" -> exploreRule.bookList = it.value
|
||||||
@@ -429,11 +449,30 @@ class BookSourceEditActivity :
|
|||||||
"payAction" -> contentRule.payAction = it.value
|
"payAction" -> contentRule.payAction = it.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reviewEntities.forEach {
|
||||||
|
when (it.key) {
|
||||||
|
"reviewUrl" -> reviewRule.reviewUrl = it.value
|
||||||
|
"avatarRule" -> reviewRule.avatarRule =
|
||||||
|
viewModel.ruleComplete(it.value, reviewRule.reviewUrl, 3)
|
||||||
|
"contentRule" -> reviewRule.contentRule =
|
||||||
|
viewModel.ruleComplete(it.value, reviewRule.reviewUrl)
|
||||||
|
"postTimeRule" -> reviewRule.postTimeRule =
|
||||||
|
viewModel.ruleComplete(it.value, reviewRule.reviewUrl)
|
||||||
|
"reviewQuoteUrl" -> reviewRule.reviewQuoteUrl =
|
||||||
|
viewModel.ruleComplete(it.value, reviewRule.reviewUrl, 2)
|
||||||
|
"voteUpUrl" -> reviewRule.voteUpUrl = it.value
|
||||||
|
"voteDownUrl" -> reviewRule.voteDownUrl = it.value
|
||||||
|
"postReviewUrl" -> reviewRule.postReviewUrl = it.value
|
||||||
|
"postQuoteUrl" -> reviewRule.postQuoteUrl = it.value
|
||||||
|
"deleteUrl" -> reviewRule.deleteUrl =it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
source.ruleSearch = searchRule
|
source.ruleSearch = searchRule
|
||||||
source.ruleExplore = exploreRule
|
source.ruleExplore = exploreRule
|
||||||
source.ruleBookInfo = bookInfoRule
|
source.ruleBookInfo = bookInfoRule
|
||||||
source.ruleToc = tocRule
|
source.ruleToc = tocRule
|
||||||
source.ruleContent = contentRule
|
source.ruleContent = contentRule
|
||||||
|
source.ruleReview = reviewRule
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
android:text="@string/is_enable" />
|
android:text="@string/is_enable" />
|
||||||
|
|
||||||
<io.legado.app.lib.theme.view.ThemeCheckBox
|
<io.legado.app.lib.theme.view.ThemeCheckBox
|
||||||
android:id="@+id/cb_is_enable_find"
|
android:id="@+id/cb_is_enable_explore"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:checked="true"
|
android:checked="true"
|
||||||
@@ -40,18 +40,33 @@
|
|||||||
android:checked="true"
|
android:checked="true"
|
||||||
android:text="@string/auto_save_cookie" />
|
android:text="@string/auto_save_cookie" />
|
||||||
|
|
||||||
<TextView
|
<io.legado.app.lib.theme.view.ThemeCheckBox
|
||||||
|
android:id="@+id/cb_is_enable_review"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/review" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:height="30dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
android:text="@string/book_type"
|
android:text="@string/book_type"
|
||||||
android:layout_marginLeft="12dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginRight="3dp"
|
android:layout_marginRight="3dp"
|
||||||
tools:ignore="RtlHardcoded" />
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatSpinner
|
<androidx.appcompat.widget.AppCompatSpinner
|
||||||
android:id="@+id/sp_type"
|
android:id="@+id/sp_type"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:entries="@array/book_type"
|
android:entries="@array/book_type"
|
||||||
app:theme="@style/Spinner" />
|
app:theme="@style/Spinner" />
|
||||||
|
|
||||||
@@ -94,6 +109,11 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/source_tab_content" />
|
android:text="@string/source_tab_content" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/review" />
|
||||||
|
|
||||||
</com.google.android.material.tabs.TabLayout>
|
</com.google.android.material.tabs.TabLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|||||||
@@ -84,6 +84,13 @@
|
|||||||
android:checked="false"
|
android:checked="false"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_enable_review"
|
||||||
|
android:title="@string/review"
|
||||||
|
android:checkable="true"
|
||||||
|
android:checked="false"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_image_style"
|
android:id="@+id/menu_image_style"
|
||||||
android:title="@string/image_style"
|
android:title="@string/image_style"
|
||||||
|
|||||||
@@ -1010,6 +1010,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">Review</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1013,6 +1013,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">Review</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1013,6 +1013,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">Review</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1010,6 +1010,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">段评</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1012,6 +1012,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">段评</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1012,6 +1012,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">段评</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||||
<string name="pk_bookshelf_px">bookshelf_px</string>
|
<string name="pk_bookshelf_px" translatable="false">bookshelf_px</string>
|
||||||
<string name="legado_gzh">开源阅读</string>
|
<string name="legado_gzh" translatable="false">开源阅读</string>
|
||||||
<string name="email">kunfei.ge@gmail.com</string>
|
<string name="email" translatable="false">kunfei.ge@gmail.com</string>
|
||||||
|
|
||||||
<string name="source_rule_url">https://alanskycn.gitee.io/teachme/</string>
|
<string name="source_rule_url" translatable="false">https://alanskycn.gitee.io/teachme/</string>
|
||||||
<string name="this_github_url">https://github.com/gedoor/legado</string>
|
<string name="this_github_url" translatable="false">https://github.com/gedoor/legado</string>
|
||||||
<string name="contributors_url">https://github.com/gedoor/legado/graphs/contributors</string>
|
<string name="contributors_url" translatable="false">https://github.com/gedoor/legado/graphs/contributors</string>
|
||||||
<string name="home_page_url">https://gedoor.github.io</string>
|
<string name="home_page_url" translatable="false">https://gedoor.github.io</string>
|
||||||
<string name="license_url">https://github.com/gedoor/legado/blob/master/LICENSE</string>
|
<string name="license_url" translatable="false">https://github.com/gedoor/legado/blob/master/LICENSE</string>
|
||||||
<string name="latest_release_url">https://github.com/gedoor/legado/releases/latest</string>
|
<string name="latest_release_url" translatable="false">https://github.com/gedoor/legado/releases/latest</string>
|
||||||
<string name="latest_release_api">https://api.github.com/repos/gedoor/legado/releases/latest</string>
|
<string name="latest_release_api" translatable="false">https://api.github.com/repos/gedoor/legado/releases/latest</string>
|
||||||
<string name="tg_url">https://t.me/legado_channels</string>
|
<string name="tg_url" translatable="false">https://t.me/legado_channels</string>
|
||||||
<string name="discord_url">https://discord.gg/qDE52P5xGW</string>
|
<string name="discord_url" translatable="false">https://discord.gg/qDE52P5xGW</string>
|
||||||
|
|
||||||
<string name="http_ip">http://%1$s:%2$d</string>
|
<string name="http_ip" translatable="false">http://%1$s:%2$d</string>
|
||||||
<string name="git_hub">GitHub</string>
|
<string name="git_hub" translatable="false">GitHub</string>
|
||||||
<string name="diy_edit_source_group_title">【%s】</string>
|
<string name="diy_edit_source_group_title" translatable="false">【%s】</string>
|
||||||
<string name="vip_title">🔒%s</string>
|
<string name="vip_title" translatable="false">🔒%s</string>
|
||||||
<string name="payed_title">🔓%s</string>
|
<string name="payed_title" translatable="false">🔓%s</string>
|
||||||
|
|
||||||
<string name="separator">丨</string>
|
<string name="separator" translatable="false">丨</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1013,6 +1013,17 @@
|
|||||||
<string name="check_selected_interval">选中所选区间</string>
|
<string name="check_selected_interval">选中所选区间</string>
|
||||||
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_title">返回时提示放入书架</string>
|
||||||
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
<string name="show_add_to_shelf_alert_summary">阅读未放入书架的书籍在返回时提示放入书架</string>
|
||||||
|
<string name="review">Review</string>
|
||||||
|
<string name="rule_avatar">段评发布者头像(avatarRule)</string>
|
||||||
|
<string name="rule_review_url">段评URL(reviewUrl)</string>
|
||||||
|
<string name="rule_review_content">段评内容(contentRule)</string>
|
||||||
|
<string name="rule_post_time">段评发布时间(postTimeRule)</string>
|
||||||
|
<string name="rule_review_quote">段评回复URL(reviewQuoteUrl)</string>
|
||||||
|
<string name="review_vote_down">点踩URL(voteUpUrl)</string>
|
||||||
|
<string name="review_vote_up">点赞URL(voteDownUrl)</string>
|
||||||
|
<string name="post_review_url">发送回复URL(postReviewUrl)</string>
|
||||||
|
<string name="post_quote_url">发送回复段评URL(postQuoteUrl)</string>
|
||||||
|
<string name="delete_review_url">删除段评URL(deleteUrl)</string>
|
||||||
<string name="tag_explore_enabled">标志:发现已启用</string>
|
<string name="tag_explore_enabled">标志:发现已启用</string>
|
||||||
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
<string name="tag_explore_disabled">标志:发现已禁用</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user