mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-24 13:48:55 +03:00
feat(player): Add option to change fonts (#1185)
Co-authored-by: jmir1 <jhmiramon@gmail.com>
This commit is contained in:
parent
082d9e3395
commit
5567be64fb
8 changed files with 124 additions and 22 deletions
|
@ -273,6 +273,8 @@ dependencies {
|
|||
implementation(libs.arthenica.smartexceptions)
|
||||
// seeker seek bar
|
||||
implementation(libs.seeker)
|
||||
// true type parser
|
||||
implementation(libs.truetypeparser)
|
||||
}
|
||||
|
||||
androidComponents {
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.media.AudioManager
|
|||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.ParcelFileDescriptor
|
||||
|
@ -573,6 +574,21 @@ class PlayerActivity : BaseActivity() {
|
|||
MPVLib.setPropertyDouble("sub-delay", subtitlesDelay().get() / 1000.0)
|
||||
}
|
||||
|
||||
MPVLib.setPropertyString(
|
||||
"sub-fonts-dir",
|
||||
File(
|
||||
Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
getString(R.string.app_name),
|
||||
"fonts",
|
||||
).path,
|
||||
)
|
||||
|
||||
if (playerPreferences.subtitleFont().get().trim() != "") {
|
||||
MPVLib.setPropertyString("sub-font", playerPreferences.subtitleFont().get())
|
||||
} else {
|
||||
MPVLib.setPropertyString("sub-font", "Sans Serif")
|
||||
}
|
||||
|
||||
MPVLib.setPropertyString("sub-bold", if (boldSubtitles().get()) "yes" else "no")
|
||||
MPVLib.setPropertyString("sub-italic", if (italicSubtitles().get()) "yes" else "no")
|
||||
MPVLib.setPropertyInt("sub-font-size", subtitleFontSize().get())
|
||||
|
|
|
@ -76,6 +76,8 @@ class PlayerPreferences(
|
|||
|
||||
fun overrideSubsASS() = preferenceStore.getBoolean("pref_override_subtitles_ass", false)
|
||||
|
||||
fun subtitleFont() = preferenceStore.getString("pref_subtitle_font", "Sans Serif")
|
||||
|
||||
fun subtitleFontSize() = preferenceStore.getInt("pref_subtitles_font_size", 55)
|
||||
fun boldSubtitles() = preferenceStore.getBoolean("pref_bold_subtitles", false)
|
||||
fun italicSubtitles() = preferenceStore.getBoolean("pref_italic_subtitles", false)
|
||||
|
|
|
@ -66,6 +66,8 @@ private fun SubtitleColors(
|
|||
val borderColorPref = screenModel.preferences.borderColorSubtitles()
|
||||
val backgroundColorPref = screenModel.preferences.backgroundColorSubtitles()
|
||||
|
||||
val font by screenModel.preferences.subtitleFont().collectAsState()
|
||||
|
||||
Row(horizontalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.fillMaxWidth()) {
|
||||
SubtitleColorSelector(
|
||||
label = R.string.player_subtitle_text_color,
|
||||
|
@ -89,6 +91,7 @@ private fun SubtitleColors(
|
|||
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
SubtitlePreview(
|
||||
font = font,
|
||||
isBold = screenModel.preferences.boldSubtitles().collectAsState().value,
|
||||
isItalic = screenModel.preferences.italicSubtitles().collectAsState().value,
|
||||
textColor = Color(textColorPref.collectAsState().value),
|
||||
|
|
|
@ -1,26 +1,37 @@
|
|||
package eu.kanade.tachiyomi.ui.player.settings.sheets.subtitle
|
||||
|
||||
import android.os.Environment
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.SnackbarDefaults.backgroundColor
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.outlined.FormatBold
|
||||
import androidx.compose.material.icons.outlined.FormatItalic
|
||||
import androidx.compose.material.icons.outlined.FormatSize
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.yubyf.truetypeparser.TTFFile
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.presentation.components.OutlinedNumericChooser
|
||||
import eu.kanade.presentation.util.collectAsState
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -29,6 +40,7 @@ import eu.kanade.tachiyomi.ui.player.settings.PlayerSettingsScreenModel
|
|||
import `is`.xyz.mpv.MPVLib
|
||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
fun SubtitleFontPage(screenModel: PlayerSettingsScreenModel) {
|
||||
|
@ -41,6 +53,7 @@ fun SubtitleFontPage(screenModel: PlayerSettingsScreenModel) {
|
|||
private fun SubtitleFont(
|
||||
screenModel: PlayerSettingsScreenModel,
|
||||
) {
|
||||
val font by screenModel.preferences.subtitleFont().collectAsState()
|
||||
val boldSubtitles by screenModel.preferences.boldSubtitles().collectAsState()
|
||||
val italicSubtitles by screenModel.preferences.italicSubtitles().collectAsState()
|
||||
val subtitleFontSize by screenModel.preferences.subtitleFontSize().collectAsState()
|
||||
|
@ -65,6 +78,30 @@ private fun SubtitleFont(
|
|||
screenModel.preferences.subtitleFontSize().set(it)
|
||||
}
|
||||
|
||||
val updateFont: (String) -> Unit = {
|
||||
MPVLib.setPropertyString("sub-font", it)
|
||||
screenModel.preferences.subtitleFont().set(it)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
val fontList by remember {
|
||||
derivedStateOf {
|
||||
val customFonts = File(
|
||||
Environment.getExternalStorageDirectory().absolutePath +
|
||||
File.separator + context.getString(R.string.app_name) +
|
||||
File.separator,
|
||||
"fonts",
|
||||
).listFiles { file ->
|
||||
file.extension.equals("ttf", true) ||
|
||||
file.extension.equals("otf", true)
|
||||
}?.map {
|
||||
TTFFile.open(it).families.values.toTypedArray()[0] to it.absolutePath
|
||||
} ?: emptyList()
|
||||
listOf("Sans Serif" to "") + customFonts
|
||||
}
|
||||
}
|
||||
var selectingFont by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny),
|
||||
|
@ -74,11 +111,13 @@ private fun SubtitleFont(
|
|||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FormatSize,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(32.dp),
|
||||
)
|
||||
IconButton(onClick = { selectingFont = true }) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FormatSize,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(32.dp),
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedNumericChooser(
|
||||
label = stringResource(id = R.string.player_font_size_text_field),
|
||||
|
@ -111,7 +150,26 @@ private fun SubtitleFont(
|
|||
)
|
||||
}
|
||||
|
||||
DropdownMenu(expanded = selectingFont, onDismissRequest = { selectingFont = false }) {
|
||||
fontList.map {
|
||||
val fontName = it.first
|
||||
DropdownMenuItem(
|
||||
text = { Text(fontName) },
|
||||
onClick = { updateFont(fontName) },
|
||||
trailingIcon = {
|
||||
if (font == fontName) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Check,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
SubtitlePreview(
|
||||
font = font,
|
||||
isBold = boldSubtitles,
|
||||
isItalic = italicSubtitles,
|
||||
textColor = Color(textColor),
|
||||
|
|
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.player.settings.sheets.subtitle
|
|||
import android.graphics.Rect
|
||||
import android.graphics.Typeface
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
|
@ -25,6 +26,7 @@ import androidx.compose.ui.graphics.Shadow
|
|||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
|
@ -32,11 +34,13 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.yubyf.truetypeparser.TTFFile
|
||||
import eu.kanade.presentation.components.TabbedDialog
|
||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerSettingsScreenModel
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
fun SubtitleSettingsSheet(
|
||||
|
@ -71,41 +75,38 @@ fun SubtitleSettingsSheet(
|
|||
@Composable
|
||||
fun OutLineText(
|
||||
text: String,
|
||||
font: Typeface,
|
||||
outlineColor: Color = Color.Black,
|
||||
textColor: Color = Color.White,
|
||||
backgroundColor: Color = Color.Black,
|
||||
isBold: Boolean = false,
|
||||
isItalic: Boolean = false,
|
||||
backgroundColor: Color = Color.Black,
|
||||
) {
|
||||
val textPaintStroke = Paint().asFrameworkPaint().apply {
|
||||
typeface = Typeface.create(
|
||||
Typeface.SANS_SERIF,
|
||||
if (isBold) FontWeight.Bold.weight else FontWeight.Normal.weight,
|
||||
isItalic,
|
||||
)
|
||||
typeface = font
|
||||
isAntiAlias = true
|
||||
style = android.graphics.Paint.Style.STROKE
|
||||
textSize = 16f
|
||||
textSize = 48f
|
||||
color = outlineColor.toArgb()
|
||||
strokeWidth = 2f
|
||||
strokeMiter = 2f
|
||||
strokeWidth = 12f
|
||||
strokeMiter = 8f
|
||||
strokeJoin = android.graphics.Paint.Join.ROUND
|
||||
// change the text alignment from left to center (basically shift the anchor point of the text)
|
||||
// keep in mind that this only affects horizontal alignment
|
||||
// https://developer.android.com/reference/android/graphics/Paint.Align
|
||||
textAlign = android.graphics.Paint.Align.CENTER
|
||||
isFakeBoldText = isBold
|
||||
textSkewX = if (isItalic) -0.25f else 0f
|
||||
}
|
||||
val textPaint = Paint().asFrameworkPaint().apply {
|
||||
typeface = Typeface.create(
|
||||
Typeface.SANS_SERIF,
|
||||
if (isBold) FontWeight.Bold.weight else FontWeight.Normal.weight,
|
||||
isItalic,
|
||||
)
|
||||
typeface = font
|
||||
isAntiAlias = true
|
||||
style = android.graphics.Paint.Style.FILL
|
||||
textSize = 16f
|
||||
textSize = 48f
|
||||
color = textColor.toArgb()
|
||||
textAlign = android.graphics.Paint.Align.CENTER
|
||||
isFakeBoldText = isBold
|
||||
textSkewX = if (isItalic) -0.25f else 0f
|
||||
}
|
||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||
drawIntoCanvas {
|
||||
|
@ -142,15 +143,31 @@ fun OutLineText(
|
|||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.P)
|
||||
@Composable
|
||||
fun SubtitlePreview(
|
||||
font: String,
|
||||
isBold: Boolean,
|
||||
isItalic: Boolean,
|
||||
textColor: Color,
|
||||
borderColor: Color,
|
||||
backgroundColor: Color,
|
||||
) {
|
||||
val fontMap = File(
|
||||
Environment.getExternalStorageDirectory().absolutePath +
|
||||
File.separator + LocalContext.current.getString(R.string.app_name) +
|
||||
File.separator,
|
||||
"fonts",
|
||||
).listFiles { file ->
|
||||
file.extension.equals("ttf", true) ||
|
||||
file.extension.equals("otf", true)
|
||||
}?.associateBy(
|
||||
{ TTFFile.open(it).families.values.toTypedArray()[0] },
|
||||
{ it.absolutePath },
|
||||
) ?: emptyMap()
|
||||
|
||||
val fontFile = fontMap.keys.firstOrNull { it.contains(font, true) }
|
||||
?.let { Typeface.createFromFile(fontMap[it]?.let(::File)) } ?: Typeface.SANS_SERIF
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(vertical = MaterialTheme.padding.medium)
|
||||
|
@ -160,6 +177,7 @@ fun SubtitlePreview(
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
OutLineText(
|
||||
text = stringResource(R.string.player_subtitle_settings_example),
|
||||
font = fontFile,
|
||||
outlineColor = borderColor,
|
||||
textColor = textColor,
|
||||
isBold = isBold,
|
||||
|
|
|
@ -97,6 +97,8 @@ arthenica-smartexceptions = "com.arthenica:smart-exception-java:0.1.1"
|
|||
|
||||
seeker = "io.github.2307vivek:seeker:1.1.1"
|
||||
|
||||
truetypeparser = "io.github.yubyf:truetypeparser-light:2.1.4"
|
||||
|
||||
[bundles]
|
||||
reactivex = ["rxandroid", "rxjava", "rxrelay"]
|
||||
okhttp = ["okhttp-core", "okhttp-logging", "okhttp-dnsoverhttps"]
|
||||
|
|
|
@ -345,6 +345,7 @@
|
|||
<string name="player_subtitle_text_color">Text</string>
|
||||
<string name="player_subtitle_border_color">Border</string>
|
||||
<string name="player_subtitle_background_color">Background</string>
|
||||
<string name="player_subtitle_font_text_field">Font Name</string>
|
||||
|
||||
<!-- TachiyomiSY -->
|
||||
<string name="data_saver_exclude">Exclude from data saver</string>
|
||||
|
|
Loading…
Reference in a new issue