[修复] 书籍封面作者显示不足
[新增] 书籍封面字体颜色自定义、描边选择开关、阴影颜色自定义与开关
This commit is contained in:
+1
-1
@@ -124,7 +124,7 @@ android {
|
|||||||
}
|
}
|
||||||
manifestPlaceholders.put("app_name", "@string/app_name")
|
manifestPlaceholders.put("app_name", "@string/app_name")
|
||||||
|
|
||||||
//applicationIdSuffix '.debug'
|
applicationIdSuffix '.debug'
|
||||||
versionNameSuffix "_debug+${getGitCommitHash()}"
|
versionNameSuffix "_debug+${getGitCommitHash()}"
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'cronet-proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro', 'cronet-proguard-rules.pro'
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ object PreferKey {
|
|||||||
const val loadCoverOnlyWifi = "loadCoverOnlyWifi"
|
const val loadCoverOnlyWifi = "loadCoverOnlyWifi"
|
||||||
const val coverShowName = "coverShowName"
|
const val coverShowName = "coverShowName"
|
||||||
const val coverShowAuthor = "coverShowAuthor"
|
const val coverShowAuthor = "coverShowAuthor"
|
||||||
|
const val coverShowShadow = "coverShowShadow"
|
||||||
|
const val coverShowStroke = "coverShowStroke"
|
||||||
|
const val coverTextColor = "coverTextColor"
|
||||||
|
const val coverTextColorN = "coverTextColorN"
|
||||||
|
const val coverShadowColor = "coverShadowColor"
|
||||||
|
const val coverShadowColorN = "coverShadowColorN"
|
||||||
|
const val coverDefaultColor = "coverDefaultColor"
|
||||||
const val coverShowNameN = "coverShowNameN"
|
const val coverShowNameN = "coverShowNameN"
|
||||||
const val coverShowAuthorN = "coverShowAuthorN"
|
const val coverShowAuthorN = "coverShowAuthorN"
|
||||||
const val remoteServerId = "remoteServerId"
|
const val remoteServerId = "remoteServerId"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.legado.app.model
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.core.graphics.drawable.toDrawable
|
import androidx.core.graphics.drawable.toDrawable
|
||||||
@@ -35,10 +36,11 @@ import io.legado.app.utils.BitmapUtils
|
|||||||
import io.legado.app.utils.GSON
|
import io.legado.app.utils.GSON
|
||||||
import io.legado.app.utils.fromJsonObject
|
import io.legado.app.utils.fromJsonObject
|
||||||
import io.legado.app.utils.getPrefBoolean
|
import io.legado.app.utils.getPrefBoolean
|
||||||
|
import io.legado.app.utils.getPrefInt
|
||||||
import io.legado.app.utils.getPrefString
|
import io.legado.app.utils.getPrefString
|
||||||
|
import kotlinx.coroutines.currentCoroutineContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.coroutines.coroutineContext
|
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
object BookCover {
|
object BookCover {
|
||||||
@@ -48,6 +50,20 @@ object BookCover {
|
|||||||
private set
|
private set
|
||||||
var drawBookAuthor = true
|
var drawBookAuthor = true
|
||||||
private set
|
private set
|
||||||
|
var drawBookShadow = true
|
||||||
|
private set
|
||||||
|
var drawBookStroke = true
|
||||||
|
private set
|
||||||
|
var coverTextColor: Int = Color.WHITE
|
||||||
|
private set
|
||||||
|
var coverShadowColor: Int = Color.WHITE
|
||||||
|
private set
|
||||||
|
var coverTextColorN: Int = Color.WHITE
|
||||||
|
private set
|
||||||
|
var coverShadowColorN: Int = Color.WHITE
|
||||||
|
private set
|
||||||
|
var coverDefaultColor = true
|
||||||
|
private set
|
||||||
lateinit var defaultDrawable: Drawable
|
lateinit var defaultDrawable: Drawable
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -69,6 +85,21 @@ object BookCover {
|
|||||||
} else {
|
} else {
|
||||||
appCtx.getPrefBoolean(PreferKey.coverShowAuthor, true)
|
appCtx.getPrefBoolean(PreferKey.coverShowAuthor, true)
|
||||||
}
|
}
|
||||||
|
drawBookShadow =
|
||||||
|
appCtx.getPrefBoolean(PreferKey.coverShowShadow, false)
|
||||||
|
drawBookStroke =
|
||||||
|
appCtx.getPrefBoolean(PreferKey.coverShowStroke, true)
|
||||||
|
coverDefaultColor =
|
||||||
|
appCtx.getPrefBoolean(PreferKey.coverDefaultColor, true)
|
||||||
|
coverTextColor =
|
||||||
|
appCtx.getPrefInt(PreferKey.coverTextColor, Color.WHITE)
|
||||||
|
coverTextColorN =
|
||||||
|
appCtx.getPrefInt(PreferKey.coverTextColorN, Color.BLACK)
|
||||||
|
coverShadowColor =
|
||||||
|
appCtx.getPrefInt(PreferKey.coverShadowColor, Color.WHITE)
|
||||||
|
coverShadowColorN =
|
||||||
|
appCtx.getPrefInt(PreferKey.coverShadowColorN, Color.BLACK)
|
||||||
|
|
||||||
val key = if (isNightTheme) PreferKey.defaultCoverDark else PreferKey.defaultCover
|
val key = if (isNightTheme) PreferKey.defaultCoverDark else PreferKey.defaultCover
|
||||||
val path = appCtx.getPrefString(key)
|
val path = appCtx.getPrefString(key)
|
||||||
if (path.isNullOrBlank()) {
|
if (path.isNullOrBlank()) {
|
||||||
@@ -222,12 +253,12 @@ object BookCover {
|
|||||||
config.searchUrl,
|
config.searchUrl,
|
||||||
book.name,
|
book.name,
|
||||||
source = config,
|
source = config,
|
||||||
coroutineContext = coroutineContext,
|
coroutineContext = currentCoroutineContext(),
|
||||||
hasLoginHeader = false
|
hasLoginHeader = false
|
||||||
)
|
)
|
||||||
val res = analyzeUrl.getStrResponseAwait()
|
val res = analyzeUrl.getStrResponseAwait()
|
||||||
val analyzeRule = AnalyzeRule(book)
|
val analyzeRule = AnalyzeRule(book)
|
||||||
analyzeRule.setCoroutineContext(coroutineContext)
|
analyzeRule.setCoroutineContext(currentCoroutineContext())
|
||||||
analyzeRule.setContent(res.body)
|
analyzeRule.setContent(res.body)
|
||||||
analyzeRule.setRedirectUrl(res.url)
|
analyzeRule.setRedirectUrl(res.url)
|
||||||
return analyzeRule.getString(config.coverRule, isUrl = true)
|
return analyzeRule.getString(config.coverRule, isUrl = true)
|
||||||
|
|||||||
@@ -74,6 +74,13 @@ class CoverConfigFragment : PreferenceFragment(),
|
|||||||
?.isEnabled = getPrefBoolean(key)
|
?.isEnabled = getPrefBoolean(key)
|
||||||
BookCover.upDefaultCover()
|
BookCover.upDefaultCover()
|
||||||
}
|
}
|
||||||
|
PreferKey.coverTextColor,
|
||||||
|
PreferKey.coverTextColorN,
|
||||||
|
PreferKey.coverShadowColor,
|
||||||
|
PreferKey.coverShadowColorN,
|
||||||
|
PreferKey.coverDefaultColor,
|
||||||
|
PreferKey.coverShowShadow,
|
||||||
|
PreferKey.coverShowStroke,
|
||||||
PreferKey.coverShowAuthor,
|
PreferKey.coverShowAuthor,
|
||||||
PreferKey.coverShowAuthorN -> {
|
PreferKey.coverShowAuthorN -> {
|
||||||
BookCover.upDefaultCover()
|
BookCover.upDefaultCover()
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import io.legado.app.constant.AppPattern
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.glide.ImageLoader
|
import io.legado.app.help.glide.ImageLoader
|
||||||
import io.legado.app.help.glide.OkHttpModelLoader
|
import io.legado.app.help.glide.OkHttpModelLoader
|
||||||
//import io.legado.app.lib.theme.accentColor
|
|
||||||
import io.legado.app.model.BookCover
|
import io.legado.app.model.BookCover
|
||||||
import io.legado.app.utils.spToPx
|
import io.legado.app.utils.spToPx
|
||||||
import io.legado.app.utils.textHeight
|
import io.legado.app.utils.textHeight
|
||||||
@@ -47,6 +46,9 @@ class CoverImageView @JvmOverloads constructor(
|
|||||||
private var author: String? = null
|
private var author: String? = null
|
||||||
private var nameHeight = 0f
|
private var nameHeight = 0f
|
||||||
private var authorHeight = 0f
|
private var authorHeight = 0f
|
||||||
|
private val isNightTheme = AppConfig.isNightTheme
|
||||||
|
val colorKey = if (isNightTheme) BookCover.coverTextColorN else BookCover.coverTextColor
|
||||||
|
val shadowKey = if (isNightTheme) BookCover.coverShadowColorN else BookCover.coverShadowColor
|
||||||
private val namePaint by lazy {
|
private val namePaint by lazy {
|
||||||
val textPaint = TextPaint()
|
val textPaint = TextPaint()
|
||||||
textPaint.typeface = Typeface.DEFAULT_BOLD
|
textPaint.typeface = Typeface.DEFAULT_BOLD
|
||||||
@@ -119,21 +121,35 @@ class CoverImageView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun drawNameAuthor(canvas: Canvas) {
|
private fun drawNameAuthor(canvas: Canvas) {
|
||||||
|
var startX = width * 0.2f
|
||||||
|
var startY = viewHeight * 0.2f
|
||||||
if (BookCover.drawBookName) {
|
if (BookCover.drawBookName) {
|
||||||
var startX = width * 0.2f
|
|
||||||
var startY = viewHeight * 0.2f
|
|
||||||
|
|
||||||
name?.toStringArray()?.let { nameChars ->
|
name?.toStringArray()?.let { nameChars ->
|
||||||
val textSize = viewWidth / 8
|
val textSize = viewWidth / 8
|
||||||
namePaint.textSize = textSize
|
namePaint.textSize = textSize
|
||||||
namePaint.strokeWidth = textSize / 8
|
namePaint.strokeWidth = textSize / 8
|
||||||
|
|
||||||
nameChars.forEach { char ->
|
if (BookCover.drawBookShadow) {
|
||||||
namePaint.color = Color.WHITE
|
namePaint.setShadowLayer(
|
||||||
namePaint.style = Paint.Style.STROKE
|
4f,
|
||||||
canvas.drawText(char, startX, startY, namePaint)
|
0f,
|
||||||
|
0f,
|
||||||
|
shadowKey
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
namePaint.clearShadowLayer()
|
||||||
|
}
|
||||||
|
|
||||||
namePaint.color = context.themeColor(androidx.appcompat.R.attr.colorPrimary)
|
nameChars.forEach { char ->
|
||||||
|
if (BookCover.drawBookStroke) {
|
||||||
|
namePaint.color = Color.WHITE
|
||||||
|
namePaint.style = Paint.Style.STROKE
|
||||||
|
canvas.drawText(char, startX, startY, namePaint)
|
||||||
|
}
|
||||||
|
if (BookCover.coverDefaultColor)
|
||||||
|
namePaint.color = context.themeColor(com.google.android.material.R.attr.colorSecondary)
|
||||||
|
else
|
||||||
|
namePaint.color = colorKey
|
||||||
namePaint.style = Paint.Style.FILL
|
namePaint.style = Paint.Style.FILL
|
||||||
canvas.drawText(char, startX, startY, namePaint)
|
canvas.drawText(char, startX, startY, namePaint)
|
||||||
|
|
||||||
@@ -144,33 +160,48 @@ class CoverImageView @JvmOverloads constructor(
|
|||||||
startY = viewHeight * 0.2f
|
startY = viewHeight * 0.2f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
namePaint.clearShadowLayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BookCover.drawBookAuthor) {
|
if (BookCover.drawBookAuthor) {
|
||||||
author?.toStringArray()?.let { authorChars ->
|
author?.toStringArray()?.let { author ->
|
||||||
val textSize = viewWidth / 10
|
authorPaint.textSize = viewWidth / 10
|
||||||
authorPaint.textSize = textSize
|
authorPaint.strokeWidth = authorPaint.textSize / 5
|
||||||
authorPaint.strokeWidth = textSize / 5
|
startX = width * 0.8f
|
||||||
|
startY = viewHeight * 0.95f - author.size * authorPaint.textHeight
|
||||||
|
startY = maxOf(startY, viewHeight * 0.2f)
|
||||||
|
if (BookCover.drawBookShadow) {
|
||||||
|
authorPaint.setShadowLayer(
|
||||||
|
4f,
|
||||||
|
0f,
|
||||||
|
0f,
|
||||||
|
shadowKey
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
authorPaint.clearShadowLayer()
|
||||||
|
}
|
||||||
|
|
||||||
var startX = width * 0.8f
|
author.forEach {
|
||||||
var startY = viewHeight * 0.8f
|
if (BookCover.drawBookStroke) {
|
||||||
|
authorPaint.color = Color.WHITE
|
||||||
authorChars.forEach { char ->
|
authorPaint.style = Paint.Style.STROKE
|
||||||
|
canvas.drawText(it, startX, startY, authorPaint)
|
||||||
authorPaint.color = Color.WHITE
|
}
|
||||||
authorPaint.style = Paint.Style.STROKE
|
if (BookCover.coverDefaultColor)
|
||||||
canvas.drawText(char, startX, startY, authorPaint)
|
authorPaint.color = context.themeColor(com.google.android.material.R.attr.colorSecondary)
|
||||||
|
else
|
||||||
authorPaint.color =
|
authorPaint.color = colorKey
|
||||||
context.themeColor(com.google.android.material.R.attr.colorSecondary)
|
|
||||||
authorPaint.style = Paint.Style.FILL
|
authorPaint.style = Paint.Style.FILL
|
||||||
canvas.drawText(char, startX, startY, authorPaint)
|
canvas.drawText(it, startX, startY, authorPaint)
|
||||||
|
|
||||||
startY += authorPaint.textHeight
|
startY += authorPaint.textHeight
|
||||||
|
|
||||||
if (startY > viewHeight * 0.95f) return@let
|
if (startY > viewHeight * 0.95) {
|
||||||
|
return@let
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
authorPaint.clearShadowLayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1356,4 +1356,7 @@
|
|||||||
<string name="is_read_finished">已读</string>
|
<string name="is_read_finished">已读</string>
|
||||||
<string name="manga">漫画</string>
|
<string name="manga">漫画</string>
|
||||||
<string name="noval">小说</string>
|
<string name="noval">小说</string>
|
||||||
|
<string name="cover_show_shadow">显示字体阴影</string>
|
||||||
|
<string name="cover_show_stroke">显示字体描边</string>
|
||||||
|
<string name="default_color">使用默认字体颜色</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -589,7 +589,6 @@
|
|||||||
<color name="disabled">@color/md_light_disabled</color>
|
<color name="disabled">@color/md_light_disabled</color>
|
||||||
|
|
||||||
<color name="divider">#66666666</color>
|
<color name="divider">#66666666</color>
|
||||||
|
|
||||||
<color name="lightBlue_color">#FF578FCC</color>
|
<color name="lightBlue_color">#FF578FCC</color>
|
||||||
|
|
||||||
<color name="error">#eb4333</color>
|
<color name="error">#eb4333</color>
|
||||||
|
|||||||
@@ -1359,4 +1359,7 @@
|
|||||||
<string name="is_read_finished">已读</string>
|
<string name="is_read_finished">已读</string>
|
||||||
<string name="manga">漫画</string>
|
<string name="manga">漫画</string>
|
||||||
<string name="noval">小说</string>
|
<string name="noval">小说</string>
|
||||||
|
<string name="cover_show_shadow">显示字体阴影</string>
|
||||||
|
<string name="cover_show_stroke">显示字体描边</string>
|
||||||
|
<string name="default_color">使用默认字体颜色</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -25,6 +25,29 @@
|
|||||||
app:allowDividerBelow="false"
|
app:allowDividerBelow="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
|
android:key="coverShowShadow"
|
||||||
|
android:title="@string/cover_show_shadow"
|
||||||
|
app:allowDividerAbove="false"
|
||||||
|
app:allowDividerBelow="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
|
android:key="coverShowStroke"
|
||||||
|
android:title="@string/cover_show_stroke"
|
||||||
|
android:defaultValue="true"
|
||||||
|
app:allowDividerAbove="false"
|
||||||
|
app:allowDividerBelow="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
|
android:key="coverDefaultColor"
|
||||||
|
android:title="@string/default_color"
|
||||||
|
android:defaultValue="true"
|
||||||
|
app:allowDividerAbove="false"
|
||||||
|
app:allowDividerBelow="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<io.legado.app.lib.prefs.PreferenceCategory
|
<io.legado.app.lib.prefs.PreferenceCategory
|
||||||
android:key="dayThemeCategory"
|
android:key="dayThemeCategory"
|
||||||
android:title="@string/day"
|
android:title="@string/day"
|
||||||
@@ -40,6 +63,20 @@
|
|||||||
app:allowDividerBelow="false"
|
app:allowDividerBelow="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.ColorPreference
|
||||||
|
android:defaultValue="@color/md_green_500"
|
||||||
|
android:key="coverTextColor"
|
||||||
|
android:title="@string/text_color"
|
||||||
|
app:cpv_dialogType="preset"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.ColorPreference
|
||||||
|
android:defaultValue="@color/md_green_500"
|
||||||
|
android:key="coverShadowColor"
|
||||||
|
android:title="@string/text_shadow_color"
|
||||||
|
app:cpv_dialogType="preset"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<io.legado.app.lib.prefs.SwitchPreference
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="coverShowName"
|
android:key="coverShowName"
|
||||||
@@ -75,6 +112,20 @@
|
|||||||
app:allowDividerBelow="false"
|
app:allowDividerBelow="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.ColorPreference
|
||||||
|
android:defaultValue="@color/md_green_500"
|
||||||
|
android:key="coverTextColorN"
|
||||||
|
android:title="@string/text_color"
|
||||||
|
app:cpv_dialogType="preset"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.prefs.ColorPreference
|
||||||
|
android:defaultValue="@color/md_green_500"
|
||||||
|
android:key="coverShadowColorN"
|
||||||
|
android:title="@string/text_shadow_color"
|
||||||
|
app:cpv_dialogType="preset"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<io.legado.app.lib.prefs.SwitchPreference
|
<io.legado.app.lib.prefs.SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="coverShowNameN"
|
android:key="coverShowNameN"
|
||||||
|
|||||||
Reference in New Issue
Block a user