feat(exoplayer): custom subtitle view (#544)
* branch * Add Custom Subtitles
This commit is contained in:
parent
eac4604b3d
commit
b04a176870
7 changed files with 478 additions and 49 deletions
|
@ -12,6 +12,7 @@ import android.content.Intent
|
|||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.hardware.SensorManager
|
||||
|
@ -71,9 +72,12 @@ import androidx.media3.common.MimeTypes
|
|||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.PlaybackParameters
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.text.Cue
|
||||
import androidx.media3.common.text.CueGroup
|
||||
import androidx.media3.common.TrackGroup
|
||||
import androidx.media3.common.TrackSelectionOverride
|
||||
import androidx.media3.common.Tracks
|
||||
import androidx.media3.common.util.Util
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.datasource.DataSource
|
||||
import androidx.media3.datasource.DefaultDataSource
|
||||
|
@ -137,6 +141,7 @@ import ani.dantotsu.others.getSerialized
|
|||
import ani.dantotsu.parsers.AnimeSources
|
||||
import ani.dantotsu.parsers.HAnimeSources
|
||||
import ani.dantotsu.parsers.Subtitle
|
||||
import ani.dantotsu.others.Xubtitle
|
||||
import ani.dantotsu.parsers.SubtitleType
|
||||
import ani.dantotsu.parsers.Video
|
||||
import ani.dantotsu.parsers.VideoExtractor
|
||||
|
@ -226,6 +231,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
private lateinit var animeTitle: TextView
|
||||
private lateinit var videoInfo: TextView
|
||||
private lateinit var episodeTitle: Spinner
|
||||
private lateinit var customSubtitleView: Xubtitle
|
||||
|
||||
private var orientationListener: OrientationEventListener? = null
|
||||
|
||||
|
@ -425,6 +431,95 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
}
|
||||
}
|
||||
|
||||
private fun applySubtitleStyles(textView: Xubtitle) {
|
||||
val primaryColor = when (PrefManager.getVal<Int>(PrefName.PrimaryColor)) {
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
else -> Color.WHITE
|
||||
}
|
||||
|
||||
val subBackground = when (PrefManager.getVal<Int>(PrefName.SubBackground)) {
|
||||
0 -> Color.TRANSPARENT
|
||||
1 -> Color.BLACK
|
||||
2 -> Color.DKGRAY
|
||||
3 -> Color.GRAY
|
||||
4 -> Color.LTGRAY
|
||||
5 -> Color.WHITE
|
||||
6 -> Color.RED
|
||||
7 -> Color.YELLOW
|
||||
8 -> Color.GREEN
|
||||
9 -> Color.CYAN
|
||||
10 -> Color.BLUE
|
||||
11 -> Color.MAGENTA
|
||||
else -> Color.TRANSPARENT
|
||||
}
|
||||
|
||||
val font = when (PrefManager.getVal<Int>(PrefName.Font)) {
|
||||
0 -> ResourcesCompat.getFont(this, R.font.poppins_semi_bold)
|
||||
1 -> ResourcesCompat.getFont(this, R.font.poppins_bold)
|
||||
2 -> ResourcesCompat.getFont(this, R.font.poppins)
|
||||
3 -> ResourcesCompat.getFont(this, R.font.poppins_thin)
|
||||
4 -> ResourcesCompat.getFont(this, R.font.century_gothic_regular)
|
||||
5 -> ResourcesCompat.getFont(this, R.font.levenim_mt_bold)
|
||||
6 -> ResourcesCompat.getFont(this, R.font.blocky)
|
||||
else -> ResourcesCompat.getFont(this, R.font.poppins_semi_bold)
|
||||
}
|
||||
|
||||
val fontSize = PrefManager.getVal<Int>(PrefName.FontSize).toFloat()
|
||||
|
||||
textView.setBackgroundColor(subBackground)
|
||||
textView.setTextColor(primaryColor)
|
||||
textView.typeface = font
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize)
|
||||
|
||||
val secondaryColor = when (PrefManager.getVal<Int>(PrefName.SecondaryColor)) {
|
||||
0 -> Color.BLACK
|
||||
1 -> Color.DKGRAY
|
||||
2 -> Color.GRAY
|
||||
3 -> Color.LTGRAY
|
||||
4 -> Color.WHITE
|
||||
5 -> Color.RED
|
||||
6 -> Color.YELLOW
|
||||
7 -> Color.GREEN
|
||||
8 -> Color.CYAN
|
||||
9 -> Color.BLUE
|
||||
10 -> Color.MAGENTA
|
||||
11 -> Color.TRANSPARENT
|
||||
else -> Color.BLACK
|
||||
}
|
||||
|
||||
val subStroke = PrefManager.getVal<Float>(PrefName.SubStroke)
|
||||
|
||||
textView.apply {
|
||||
when (PrefManager.getVal<Int>(PrefName.Outline)) {
|
||||
0 -> applyOutline(secondaryColor, subStroke)
|
||||
1 -> applyShineEffect(secondaryColor)
|
||||
2 -> applyDropShadow(secondaryColor, subStroke)
|
||||
3 -> {}
|
||||
else -> applyOutline(secondaryColor, subStroke)
|
||||
}
|
||||
}
|
||||
|
||||
textView.alpha =
|
||||
when (PrefManager.getVal<Boolean>(PrefName.Subtitles)) {
|
||||
true -> PrefManager.getVal(PrefName.SubAlpha)
|
||||
false -> 0f
|
||||
}
|
||||
|
||||
val textElevation = PrefManager.getVal<Float>(PrefName.SubBottomMargin) / 30 * resources.displayMetrics.heightPixels
|
||||
textView.translationY = -textElevation
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
@ -470,6 +565,7 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
skipTimeButton = playerView.findViewById(R.id.exo_skip_timestamp)
|
||||
skipTimeText = skipTimeButton.findViewById(R.id.exo_skip_timestamp_text)
|
||||
timeStampText = playerView.findViewById(R.id.exo_time_stamp_text)
|
||||
customSubtitleView = playerView.findViewById(R.id.customSubtitleView)
|
||||
|
||||
animeTitle = playerView.findViewById(R.id.exo_anime_title)
|
||||
episodeTitle = playerView.findViewById(R.id.exo_ep_sel)
|
||||
|
@ -523,7 +619,6 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
it.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
setupSubFormatting(playerView)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
currentWindow = savedInstanceState.getInt(resumeWindow)
|
||||
|
@ -1732,6 +1827,54 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
}
|
||||
playerView.player = exoPlayer
|
||||
|
||||
exoPlayer.addListener(object : Player.Listener {
|
||||
var activeSubtitles = ArrayDeque<String>(3)
|
||||
var lastSubtitle: String? = null
|
||||
var lastPosition: Long = 0
|
||||
|
||||
override fun onCues(cueGroup: CueGroup) {
|
||||
if (PrefManager.getVal<Boolean>(PrefName.TextviewSubtitles)) {
|
||||
exoSubtitleView.visibility = View.GONE
|
||||
customSubtitleView.visibility = View.VISIBLE
|
||||
val newCues = cueGroup.cues.map { it.text.toString() ?: "" }
|
||||
|
||||
if (newCues.isEmpty()) {
|
||||
customSubtitleView.text = ""
|
||||
activeSubtitles.clear()
|
||||
lastSubtitle = null
|
||||
lastPosition = 0
|
||||
return
|
||||
}
|
||||
|
||||
val currentPosition = exoPlayer.currentPosition
|
||||
|
||||
if ((lastSubtitle?.length ?: 0) < 20 || (lastPosition != 0L && currentPosition - lastPosition > 1500)) {
|
||||
activeSubtitles.clear()
|
||||
}
|
||||
|
||||
for (newCue in newCues) {
|
||||
if (newCue !in activeSubtitles) {
|
||||
if (activeSubtitles.size >= 2) {
|
||||
activeSubtitles.removeLast()
|
||||
}
|
||||
activeSubtitles.addFirst(newCue)
|
||||
lastSubtitle = newCue
|
||||
lastPosition = currentPosition
|
||||
}
|
||||
}
|
||||
|
||||
customSubtitleView.text = activeSubtitles.joinToString("\n")
|
||||
} else {
|
||||
customSubtitleView.text = ""
|
||||
customSubtitleView.visibility = View.GONE
|
||||
exoSubtitleView.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
applySubtitleStyles(customSubtitleView)
|
||||
setupSubFormatting(playerView)
|
||||
|
||||
try {
|
||||
val rightNow = Calendar.getInstance()
|
||||
mediaSession = MediaSession.Builder(this, exoPlayer)
|
||||
|
@ -2021,7 +2164,10 @@ class ExoplayerView : AppCompatActivity(), Player.Listener, SessionAvailabilityL
|
|||
TrackSelectionOverride(trackGroup.mediaTrackGroup, index)
|
||||
)
|
||||
.build()
|
||||
if (type == TRACK_TYPE_TEXT) setupSubFormatting(playerView)
|
||||
if (type == TRACK_TYPE_TEXT) {
|
||||
setupSubFormatting(playerView)
|
||||
applySubtitleStyles(customSubtitleView)
|
||||
}
|
||||
playerView.subtitleView?.alpha = when (isDisabled) {
|
||||
false -> PrefManager.getVal(PrefName.SubAlpha)
|
||||
true -> 0f
|
||||
|
|
144
app/src/main/java/ani/dantotsu/others/Xubtitle.kt
Normal file
144
app/src/main/java/ani/dantotsu/others/Xubtitle.kt
Normal file
|
@ -0,0 +1,144 @@
|
|||
package ani.dantotsu.others
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.LinearGradient
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Shader
|
||||
import android.text.Layout
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextPaint
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
|
||||
class Xubtitle
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
) : AppCompatTextView(context, attrs, defStyleAttr) {
|
||||
private var outlineThickness: Float = 0f
|
||||
private var effectColor: Int = currentTextColor
|
||||
private var currentEffect: Effect = Effect.NONE
|
||||
|
||||
private val shadowPaint = Paint().apply { isAntiAlias = true }
|
||||
private val outlinePaint = Paint().apply { isAntiAlias = true }
|
||||
private var shineShader: Shader? = null
|
||||
|
||||
enum class Effect {
|
||||
NONE,
|
||||
OUTLINE,
|
||||
SHINE,
|
||||
DROP_SHADOW,
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
val text = text.toString()
|
||||
val textPaint =
|
||||
TextPaint(paint).apply {
|
||||
color = currentTextColor
|
||||
}
|
||||
val staticLayout =
|
||||
StaticLayout.Builder
|
||||
.obtain(text, 0, text.length, textPaint, width)
|
||||
.setAlignment(Layout.Alignment.ALIGN_CENTER)
|
||||
.setLineSpacing(0f, 1f)
|
||||
.build()
|
||||
|
||||
when (currentEffect) {
|
||||
Effect.OUTLINE -> {
|
||||
textPaint.style = Paint.Style.STROKE
|
||||
textPaint.strokeWidth = outlineThickness
|
||||
textPaint.color = effectColor
|
||||
|
||||
staticLayout.draw(canvas)
|
||||
|
||||
textPaint.style = Paint.Style.FILL
|
||||
textPaint.color = currentTextColor
|
||||
staticLayout.draw(canvas)
|
||||
}
|
||||
|
||||
Effect.DROP_SHADOW -> {
|
||||
setLayerType(LAYER_TYPE_SOFTWARE, null)
|
||||
textPaint.setShadowLayer(outlineThickness, 4f, 4f, effectColor)
|
||||
|
||||
staticLayout.draw(canvas)
|
||||
|
||||
textPaint.clearShadowLayer()
|
||||
}
|
||||
|
||||
Effect.SHINE -> {
|
||||
val shadowShader =
|
||||
LinearGradient(
|
||||
0f,
|
||||
0f,
|
||||
width.toFloat(),
|
||||
height.toFloat(),
|
||||
intArrayOf(Color.WHITE, effectColor, Color.BLACK),
|
||||
null,
|
||||
Shader.TileMode.CLAMP,
|
||||
)
|
||||
|
||||
val shadowPaint =
|
||||
Paint().apply {
|
||||
isAntiAlias = true
|
||||
style = Paint.Style.FILL
|
||||
textSize = textPaint.textSize
|
||||
typeface = textPaint.typeface
|
||||
shader = shadowShader
|
||||
}
|
||||
|
||||
canvas.drawText(
|
||||
text,
|
||||
x + 4f, // Shadow offset
|
||||
y + 4f,
|
||||
shadowPaint,
|
||||
)
|
||||
|
||||
val shader =
|
||||
LinearGradient(
|
||||
0f,
|
||||
0f,
|
||||
width.toFloat(),
|
||||
height.toFloat(),
|
||||
intArrayOf(effectColor, Color.WHITE, Color.WHITE),
|
||||
null,
|
||||
Shader.TileMode.CLAMP,
|
||||
)
|
||||
textPaint.shader = shader
|
||||
staticLayout.draw(canvas)
|
||||
textPaint.shader = null
|
||||
}
|
||||
|
||||
Effect.NONE -> {
|
||||
staticLayout.draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun applyOutline(
|
||||
color: Int,
|
||||
outlineThickness: Float,
|
||||
) {
|
||||
this.effectColor = color
|
||||
this.outlineThickness = outlineThickness
|
||||
currentEffect = Effect.OUTLINE
|
||||
}
|
||||
|
||||
// Too hard for me to figure it out
|
||||
fun applyShineEffect(color: Int) {
|
||||
this.effectColor = color
|
||||
currentEffect = Effect.SHINE
|
||||
}
|
||||
|
||||
fun applyDropShadow(
|
||||
color: Int,
|
||||
outlineThickness: Float,
|
||||
) {
|
||||
this.effectColor = color
|
||||
this.outlineThickness = outlineThickness
|
||||
currentEffect = Effect.DROP_SHADOW
|
||||
}
|
||||
}
|
|
@ -267,16 +267,16 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
|||
PrefManager.setVal(PrefName.Cast, isChecked)
|
||||
}
|
||||
|
||||
binding.playerSettingsInternalCast.isChecked = PrefManager.getVal(PrefName.UseInternalCast)
|
||||
binding.playerSettingsInternalCast.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.UseInternalCast, isChecked)
|
||||
}
|
||||
|
||||
binding.playerSettingsRotate.isChecked = PrefManager.getVal(PrefName.RotationPlayer)
|
||||
binding.playerSettingsRotate.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.RotationPlayer, isChecked)
|
||||
}
|
||||
|
||||
binding.playerSettingsInternalCast.isChecked = PrefManager.getVal(PrefName.UseInternalCast)
|
||||
binding.playerSettingsInternalCast.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.UseInternalCast, isChecked)
|
||||
}
|
||||
|
||||
binding.playerSettingsAdditionalCodec.isChecked = PrefManager.getVal(PrefName.UseAdditionalCodec)
|
||||
binding.playerSettingsAdditionalCodec.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.UseAdditionalCodec, isChecked)
|
||||
|
@ -306,23 +306,50 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
|||
binding.videoSubColorWindow,
|
||||
binding.videoSubFont,
|
||||
binding.videoSubAlpha,
|
||||
binding.videoSubStroke,
|
||||
binding.subtitleFontSizeText,
|
||||
binding.subtitleFontSize
|
||||
binding.subtitleFontSize,
|
||||
binding.videoSubLanguage,
|
||||
binding.subTextSwitch
|
||||
).forEach {
|
||||
it.isEnabled = isChecked
|
||||
it.isClickable = isChecked
|
||||
it.alpha = when (isChecked) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleExpSubOptions(isChecked: Boolean) {
|
||||
arrayOf(
|
||||
binding.videoSubStrokeButton,
|
||||
binding.videoSubStroke,
|
||||
binding.videoSubBottomMarginButton,
|
||||
binding.videoSubBottomMargin
|
||||
).forEach {
|
||||
it.isEnabled = isChecked
|
||||
it.alpha = when (isChecked) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.subSwitch.isChecked = PrefManager.getVal(PrefName.Subtitles)
|
||||
binding.subSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.Subtitles, isChecked)
|
||||
toggleSubOptions(isChecked)
|
||||
toggleExpSubOptions(binding.subTextSwitch.isChecked && isChecked)
|
||||
}
|
||||
toggleSubOptions(binding.subSwitch.isChecked)
|
||||
|
||||
binding.subTextSwitch.isChecked = PrefManager.getVal(PrefName.TextviewSubtitles)
|
||||
binding.subTextSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
PrefManager.setVal(PrefName.TextviewSubtitles, isChecked)
|
||||
toggleExpSubOptions(isChecked)
|
||||
}
|
||||
toggleExpSubOptions(binding.subTextSwitch.isChecked)
|
||||
|
||||
val subLanguages = arrayOf(
|
||||
"Albanian",
|
||||
"Arabic",
|
||||
|
@ -366,17 +393,17 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
|||
"Urdu",
|
||||
"Vietnamese",
|
||||
)
|
||||
val subLanguageDialog = AlertDialog.Builder(this, R.style.MyPopup)
|
||||
.setTitle(getString(R.string.subtitle_langauge))
|
||||
binding.videoSubLanguage.setOnClickListener {
|
||||
val dialog = subLanguageDialog.setSingleChoiceItems(
|
||||
subLanguages,
|
||||
PrefManager.getVal(PrefName.SubLanguage)
|
||||
) { dialog, count ->
|
||||
PrefManager.setVal(PrefName.SubLanguage, count)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
dialog.window?.setDimAmount(0.8f)
|
||||
customAlertDialog().apply {
|
||||
setTitle(getString(R.string.subtitle_langauge))
|
||||
singleChoiceItems(
|
||||
subLanguages,
|
||||
PrefManager.getVal(PrefName.SubLanguage)
|
||||
) { count ->
|
||||
PrefManager.setVal(PrefName.SubLanguage, count)
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
val colorsPrimary =
|
||||
arrayOf(
|
||||
|
@ -510,6 +537,22 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
|||
}
|
||||
})
|
||||
|
||||
binding.videoSubStroke.value = PrefManager.getVal(PrefName.SubStroke)
|
||||
binding.videoSubStroke.addOnChangeListener(OnChangeListener { _, value, fromUser ->
|
||||
if (fromUser) {
|
||||
PrefManager.setVal(PrefName.SubStroke, value)
|
||||
updateSubPreview()
|
||||
}
|
||||
})
|
||||
|
||||
binding.videoSubBottomMargin.value = PrefManager.getVal(PrefName.SubBottomMargin)
|
||||
binding.videoSubBottomMargin.addOnChangeListener(OnChangeListener { _, value, fromUser ->
|
||||
if (fromUser) {
|
||||
PrefManager.setVal(PrefName.SubBottomMargin, value)
|
||||
updateSubPreview()
|
||||
}
|
||||
})
|
||||
|
||||
val fonts = arrayOf(
|
||||
"Poppins Semi Bold",
|
||||
"Poppins Bold",
|
||||
|
|
|
@ -94,6 +94,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
|||
CursedSpeeds(Pref(Location.Player, Boolean::class, false)),
|
||||
Resize(Pref(Location.Player, Int::class, 0)),
|
||||
Subtitles(Pref(Location.Player, Boolean::class, true)),
|
||||
TextviewSubtitles(Pref(Location.Player, Boolean::class, false)),
|
||||
SubLanguage(Pref(Location.Player, Int::class, 9)),
|
||||
PrimaryColor(Pref(Location.Player, Int::class, 4)),
|
||||
SecondaryColor(Pref(Location.Player, Int::class, 0)),
|
||||
|
@ -101,6 +102,8 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
|||
SubBackground(Pref(Location.Player, Int::class, 0)),
|
||||
SubWindow(Pref(Location.Player, Int::class, 0)),
|
||||
SubAlpha(Pref(Location.Player, Float::class, 1f)),
|
||||
SubStroke(Pref(Location.Player, Float::class, 8f)),
|
||||
SubBottomMargin(Pref(Location.Player, Float::class, 4f)),
|
||||
Font(Pref(Location.Player, Int::class, 0)),
|
||||
FontSize(Pref(Location.Player, Int::class, 20)),
|
||||
Locale(Pref(Location.Player, Int::class, 2)),
|
||||
|
@ -128,7 +131,7 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
|||
Pip(Pref(Location.Player, Boolean::class, true)),
|
||||
RotationPlayer(Pref(Location.Player, Boolean::class, true)),
|
||||
TorrentEnabled(Pref(Location.Player, Boolean::class, false)),
|
||||
UseAdditionalCodec(Pref(Location.Player, Boolean::class, true)),
|
||||
UseAdditionalCodec(Pref(Location.Player, Boolean::class, false)),
|
||||
|
||||
//Reader
|
||||
ShowSource(Pref(Location.Reader, Boolean::class, true)),
|
||||
|
|
|
@ -381,6 +381,88 @@
|
|||
|
||||
</com.google.android.material.slider.Slider>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/subTextSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:checked="true"
|
||||
android:drawableStart="@drawable/ic_round_subtitles_24"
|
||||
android:drawablePadding="16dp"
|
||||
android:elegantTextHeight="false"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:minHeight="64dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/textview_sub"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/videoSubStrokeButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clickable="false"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/textview_sub_stroke"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_color_24"
|
||||
app:iconPadding="16dp"
|
||||
app:iconSize="24dp" />
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/videoSubStroke"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:valueFrom="1"
|
||||
android:stepSize="1.0"
|
||||
android:valueTo="30">
|
||||
|
||||
</com.google.android.material.slider.Slider>
|
||||
|
||||
<Button
|
||||
android:id="@+id/videoSubBottomMarginButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clickable="false"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/textview_sub_bottom_margin"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/bg_opp"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_round_color_24"
|
||||
app:iconPadding="16dp"
|
||||
app:iconSize="24dp" />
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/videoSubBottomMargin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="32dp"
|
||||
android:valueFrom="1"
|
||||
android:stepSize="1.0"
|
||||
android:valueTo="30">
|
||||
|
||||
</com.google.android.material.slider.Slider>
|
||||
|
||||
<Button
|
||||
android:id="@+id/videoSubFont"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
|
@ -1189,27 +1271,6 @@
|
|||
|
||||
</com.google.android.material.materialswitch.MaterialSwitch>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/playerSettingsInternalCast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:drawableStart="@drawable/cast_warning"
|
||||
android:drawablePadding="16dp"
|
||||
android:elegantTextHeight="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:minHeight="64dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/try_internal_cast_experimental"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
|
||||
</com.google.android.material.materialswitch.MaterialSwitch>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/playerSettingsRotate"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1232,6 +1293,27 @@
|
|||
|
||||
</com.google.android.material.materialswitch.MaterialSwitch>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/playerSettingsInternalCast"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="false"
|
||||
android:drawableStart="@drawable/cast_warning"
|
||||
android:drawablePadding="16dp"
|
||||
android:elegantTextHeight="true"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:minHeight="64dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/try_internal_cast_experimental"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="@color/bg_opp"
|
||||
app:cornerRadius="0dp"
|
||||
app:drawableTint="?attr/colorPrimary"
|
||||
app:showText="false"
|
||||
app:thumbTint="@color/button_switch_track">
|
||||
|
||||
</com.google.android.material.materialswitch.MaterialSwitch>
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/playerSettingsAdditionalCodec"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -55,6 +55,14 @@
|
|||
|
||||
</androidx.media3.ui.SubtitleView>
|
||||
|
||||
<ani.dantotsu.others.Xubtitle
|
||||
android:id="@+id/customSubtitleView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:adjustViewBounds="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/exo_full_area"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -1078,12 +1078,15 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
|
|||
<string name="host">Host</string>
|
||||
<string name="port">Port</string>
|
||||
<string name="authentication">Authentication</string>
|
||||
<string name="proxy">Socks5 Proxy</string>
|
||||
<string name="proxy_desc">Route All Your Network Traffic Through a Socks5 Proxy</string>
|
||||
<string name="proxy">SOCKS5 Proxy</string>
|
||||
<string name="proxy_desc">Route All Your Network Traffic Through a SOCKS5 Proxy</string>
|
||||
<string name="proxy_setup">Proxy Setup</string>
|
||||
<string name="proxy_setup_desc">Configure your Socks5 Proxy</string>
|
||||
<string name="clear_stored_episode">Clear Stored Episode Data</string>
|
||||
<string name="clear_stored_chapter">Clear Stored Chapter Data</string>
|
||||
<string name="use_additional_codec">Additional Codec Support</string>
|
||||
<string name="textview_sub">Textview Subtitles (Experimental)</string>
|
||||
<string name="textview_sub_stroke">Subtitle Stroke</string>
|
||||
<string name="textview_sub_bottom_margin">Bottom Margin</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue