AquaStream/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt

544 lines
20 KiB
Kotlin
Raw Normal View History

2021-08-06 20:55:11 +00:00
package com.lagradost.cloudstream3.ui.subtitles
import android.app.Activity
import android.content.Context
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
2021-08-07 01:53:45 +00:00
import androidx.annotation.FontRes
import androidx.core.content.res.ResourcesCompat
2021-08-06 20:55:11 +00:00
import androidx.fragment.app.Fragment
2022-02-12 20:20:56 +00:00
import com.fasterxml.jackson.annotation.JsonProperty
2021-08-06 20:55:11 +00:00
import com.google.android.exoplayer2.text.Cue
import com.google.android.exoplayer2.ui.CaptionStyleCompat
import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
2022-01-07 19:27:25 +00:00
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
import com.lagradost.cloudstream3.CommonActivity.showToast
2021-08-06 20:55:11 +00:00
import com.lagradost.cloudstream3.R
2022-02-18 19:29:48 +00:00
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
2021-08-06 20:55:11 +00:00
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.Event
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.SubtitleHelper
2021-08-06 20:55:11 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
2021-08-06 21:57:52 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI
2021-09-20 21:11:36 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.navigate
2021-08-06 20:55:11 +00:00
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
import kotlinx.android.synthetic.main.subtitle_settings.*
2022-04-16 23:03:18 +00:00
import java.io.File
2021-08-06 20:55:11 +00:00
const val SUBTITLE_KEY = "subtitle_settings"
const val SUBTITLE_AUTO_SELECT_KEY = "subs_auto_select"
const val SUBTITLE_DOWNLOAD_KEY = "subs_auto_download"
2021-08-06 20:55:11 +00:00
data class SaveCaptionStyle(
2022-02-12 20:20:56 +00:00
@JsonProperty("foregroundColor") var foregroundColor: Int,
@JsonProperty("backgroundColor") var backgroundColor: Int,
@JsonProperty("windowColor") var windowColor: Int,
2021-08-06 20:55:11 +00:00
@CaptionStyleCompat.EdgeType
2022-02-12 20:20:56 +00:00
@JsonProperty("edgeType") var edgeType: Int,
2022-04-16 23:03:18 +00:00
@JsonProperty("edgeColor") var edgeColor: Int,
2021-08-07 01:53:45 +00:00
@FontRes
2022-02-12 20:20:56 +00:00
@JsonProperty("typeface") var typeface: Int?,
2022-04-16 23:03:18 +00:00
@JsonProperty("typefaceFilePath") var typefaceFilePath: String?,
2021-08-06 20:55:11 +00:00
/**in dp**/
2022-02-12 20:20:56 +00:00
@JsonProperty("elevation") var elevation: Int,
2021-09-16 12:46:21 +00:00
/**in sp**/
2022-02-12 20:20:56 +00:00
@JsonProperty("fixedTextSize") var fixedTextSize: Float?,
2021-08-06 20:55:11 +00:00
)
2021-10-09 21:59:37 +00:00
const val DEF_SUBS_ELEVATION = 20
2021-08-06 20:55:11 +00:00
class SubtitlesFragment : Fragment() {
companion object {
val applyStyleEvent = Event<SaveCaptionStyle>()
2021-08-07 01:53:45 +00:00
fun Context.fromSaveToStyle(data: SaveCaptionStyle): CaptionStyleCompat {
2021-08-06 20:55:11 +00:00
return CaptionStyleCompat(
2022-01-08 19:39:22 +00:00
data.foregroundColor,
data.backgroundColor,
data.windowColor,
data.edgeType,
data.edgeColor,
2022-04-16 23:03:18 +00:00
data.typefaceFilePath?.let {
try {
// RuntimeException: Font asset not found
Typeface.createFromFile(File(it))
} catch (e: Exception) {
null
}
} ?: data.typeface?.let {
ResourcesCompat.getFont(
this,
it
)
}
?: Typeface.SANS_SERIF
2021-08-06 20:55:11 +00:00
)
}
2021-08-07 01:53:45 +00:00
fun push(activity: Activity?, hide: Boolean = true) {
2021-09-20 21:11:36 +00:00
activity.navigate(R.id.global_to_navigation_subtitles, Bundle().apply {
putBoolean("hide", hide)
})
2021-08-06 20:55:11 +00:00
}
private fun getDefColor(id: Int): Int {
return when (id) {
0 -> Color.WHITE
1 -> Color.BLACK
2 -> Color.TRANSPARENT
3 -> Color.TRANSPARENT
else -> Color.TRANSPARENT
}
}
fun Context.saveStyle(style: SaveCaptionStyle) {
this.setKey(SUBTITLE_KEY, style)
}
fun getCurrentSavedStyle(): SaveCaptionStyle {
return getKey(SUBTITLE_KEY) ?: SaveCaptionStyle(
2021-08-06 20:55:11 +00:00
getDefColor(0),
getDefColor(2),
getDefColor(3),
CaptionStyleCompat.EDGE_TYPE_OUTLINE,
getDefColor(1),
null,
2022-04-16 23:03:18 +00:00
null,
2021-10-09 21:59:37 +00:00
DEF_SUBS_ELEVATION,
2021-09-16 12:46:21 +00:00
null,
2021-08-06 20:55:11 +00:00
)
}
2022-04-16 23:03:18 +00:00
private fun Context.getSavedFonts(): List<File> {
val externalFiles = getExternalFilesDir(null) ?: return emptyList()
val fontDir = File(externalFiles.absolutePath + "/Fonts").also {
it.mkdir()
}
return fontDir.list()?.mapNotNull {
if (it.endsWith(".ttf")) {
File(fontDir.absolutePath + "/" + it)
} else null
} ?: listOf()
}
2021-08-06 20:55:11 +00:00
private fun Context.getCurrentStyle(): CaptionStyleCompat {
return fromSaveToStyle(getCurrentSavedStyle())
}
private fun getPixels(unit: Int, size: Float): Int {
val metrics: DisplayMetrics = Resources.getSystem().displayMetrics
return TypedValue.applyDimension(unit, size, metrics).toInt()
}
fun getDownloadSubsLanguageISO639_1(): List<String> {
return getKey(SUBTITLE_DOWNLOAD_KEY) ?: listOf("en")
}
fun getAutoSelectLanguageISO639_1(): String {
return getKey(SUBTITLE_AUTO_SELECT_KEY) ?: "en"
}
2021-08-06 20:55:11 +00:00
}
private fun onColorSelected(stuff: Pair<Int, Int>) {
2021-08-07 01:53:45 +00:00
context?.setColor(stuff.first, stuff.second)
if (hide)
activity?.hideSystemUI()
2021-08-06 21:57:52 +00:00
}
private fun onDialogDismissed(id: Int) {
2021-08-07 01:53:45 +00:00
if (hide)
activity?.hideSystemUI()
2021-08-06 20:55:11 +00:00
}
2021-08-07 01:53:45 +00:00
private fun Context.setColor(id: Int, color: Int?) {
2021-08-06 20:55:11 +00:00
val realColor = color ?: getDefColor(id)
when (id) {
0 -> state.foregroundColor = realColor
1 -> state.edgeColor = realColor
2 -> state.backgroundColor = realColor
3 -> state.windowColor = realColor
2022-01-07 19:27:25 +00:00
else -> Unit
2021-08-06 20:55:11 +00:00
}
updateState()
}
2021-08-07 01:53:45 +00:00
private fun Context.updateState() {
2021-08-06 20:55:11 +00:00
subtitle_text?.setStyle(fromSaveToStyle(state))
}
private fun getColor(id: Int): Int {
val color = when (id) {
0 -> state.foregroundColor
1 -> state.edgeColor
2 -> state.backgroundColor
3 -> state.windowColor
else -> Color.TRANSPARENT
}
return if (color == Color.TRANSPARENT) Color.BLACK else color
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return inflater.inflate(R.layout.subtitle_settings, container, false)
}
2021-08-07 01:53:45 +00:00
private lateinit var state: SaveCaptionStyle
private var hide: Boolean = true
2021-08-06 20:55:11 +00:00
override fun onDestroy() {
super.onDestroy()
2022-01-07 19:27:25 +00:00
onColorSelectedEvent -= ::onColorSelected
2021-08-06 20:55:11 +00:00
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
2021-08-07 01:53:45 +00:00
hide = arguments?.getBoolean("hide") ?: true
2022-01-07 19:27:25 +00:00
onColorSelectedEvent += ::onColorSelected
onDialogDismissedEvent += ::onDialogDismissed
2022-04-16 23:03:18 +00:00
subs_import_text?.text = getString(R.string.subs_import_text).format(
context?.getExternalFilesDir(null)?.absolutePath.toString() + "/Fonts"
)
2021-08-06 20:55:11 +00:00
context?.fixPaddingStatusbar(subs_root)
state = getCurrentSavedStyle()
2021-08-07 01:53:45 +00:00
context?.updateState()
2021-08-06 20:55:11 +00:00
2022-02-18 19:29:48 +00:00
val isTvTrueSettings = context?.isTrueTvSettings() == true
2022-01-13 13:26:41 +00:00
fun View.setFocusableInTv() {
2022-02-18 19:29:48 +00:00
this.isFocusableInTouchMode = isTvTrueSettings
2022-01-13 13:26:41 +00:00
}
2021-08-06 20:55:11 +00:00
fun View.setup(id: Int) {
2022-01-13 13:26:41 +00:00
setFocusableInTv()
2021-08-06 20:55:11 +00:00
this.setOnClickListener {
activity?.let {
ColorPickerDialog.newBuilder()
.setDialogId(id)
2021-11-17 12:25:09 +00:00
.setShowAlphaSlider(true)
2021-08-06 20:55:11 +00:00
.setColor(getColor(id))
.show(it)
}
}
this.setOnLongClickListener {
2021-08-07 01:53:45 +00:00
it.context.setColor(id, null)
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
2021-08-06 20:55:11 +00:00
return@setOnLongClickListener true
}
}
subs_text_color.setup(0)
subs_outline_color.setup(1)
subs_background_color.setup(2)
subs_window_color.setup(3)
2021-08-07 01:53:45 +00:00
val dismissCallback = {
if (hide)
activity?.hideSystemUI()
}
2022-01-13 13:26:41 +00:00
subs_subtitle_elevation.setFocusableInTv()
2021-08-06 20:55:11 +00:00
subs_subtitle_elevation.setOnClickListener { textView ->
2021-11-30 17:59:52 +00:00
val suffix = "dp"
2021-08-06 20:55:11 +00:00
val elevationTypes = listOf(
2021-11-30 17:59:52 +00:00
Pair(0, textView.context.getString(R.string.none)),
Pair(10, "10$suffix"),
Pair(20, "20$suffix"),
Pair(30, "30$suffix"),
Pair(40, "40$suffix"),
Pair(50, "50$suffix"),
Pair(60, "60$suffix"),
Pair(70, "70$suffix"),
Pair(80, "80$suffix"),
Pair(90, "90$suffix"),
Pair(100, "100$suffix"),
2021-08-06 20:55:11 +00:00
)
//showBottomDialog
2021-12-12 02:33:17 +00:00
activity?.showDialog(
2021-08-06 20:55:11 +00:00
elevationTypes.map { it.second },
elevationTypes.map { it.first }.indexOf(state.elevation),
(textView as TextView).text.toString(),
2021-08-07 01:53:45 +00:00
false,
dismissCallback
2021-08-06 20:55:11 +00:00
) { index ->
state.elevation = elevationTypes.map { it.first }[index]
2021-08-07 01:53:45 +00:00
textView.context.updateState()
if (hide)
activity?.hideSystemUI()
2021-08-06 20:55:11 +00:00
}
}
subs_subtitle_elevation.setOnLongClickListener {
2021-10-09 21:59:37 +00:00
state.elevation = DEF_SUBS_ELEVATION
2021-08-07 01:53:45 +00:00
it.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
2021-08-06 20:55:11 +00:00
return@setOnLongClickListener true
}
2022-01-13 13:26:41 +00:00
subs_edge_type.setFocusableInTv()
2021-08-06 20:55:11 +00:00
subs_edge_type.setOnClickListener { textView ->
val edgeTypes = listOf(
2022-01-08 19:39:22 +00:00
Pair(
CaptionStyleCompat.EDGE_TYPE_NONE,
textView.context.getString(R.string.subtitles_none)
),
Pair(
CaptionStyleCompat.EDGE_TYPE_OUTLINE,
textView.context.getString(R.string.subtitles_outline)
),
Pair(
CaptionStyleCompat.EDGE_TYPE_DEPRESSED,
textView.context.getString(R.string.subtitles_depressed)
),
Pair(
CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW,
textView.context.getString(R.string.subtitles_shadow)
),
Pair(
CaptionStyleCompat.EDGE_TYPE_RAISED,
textView.context.getString(R.string.subtitles_raised)
),
2021-08-06 20:55:11 +00:00
)
//showBottomDialog
2021-12-12 02:33:17 +00:00
activity?.showDialog(
2021-08-06 20:55:11 +00:00
edgeTypes.map { it.second },
edgeTypes.map { it.first }.indexOf(state.edgeType),
(textView as TextView).text.toString(),
2021-08-07 01:53:45 +00:00
false,
dismissCallback
2021-08-06 20:55:11 +00:00
) { index ->
state.edgeType = edgeTypes.map { it.first }[index]
2021-08-07 01:53:45 +00:00
textView.context.updateState()
2021-08-06 20:55:11 +00:00
}
}
subs_edge_type.setOnLongClickListener {
state.edgeType = CaptionStyleCompat.EDGE_TYPE_OUTLINE
2021-08-07 01:53:45 +00:00
it.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
2021-08-07 01:53:45 +00:00
return@setOnLongClickListener true
}
2022-01-13 13:26:41 +00:00
subs_font_size.setFocusableInTv()
2021-09-16 12:46:21 +00:00
subs_font_size.setOnClickListener { textView ->
val suffix = "sp"
val fontSizes = listOf(
2021-11-30 17:59:52 +00:00
Pair(null, textView.context.getString(R.string.normal)),
Pair(6f, "6$suffix"),
2022-03-17 11:41:04 +00:00
Pair(7f, "7$suffix"),
2021-11-30 17:59:52 +00:00
Pair(8f, "8$suffix"),
Pair(9f, "9$suffix"),
Pair(10f, "10$suffix"),
Pair(11f, "11$suffix"),
Pair(12f, "12$suffix"),
2022-03-17 11:41:04 +00:00
Pair(13f, "13$suffix"),
2021-11-30 17:59:52 +00:00
Pair(14f, "14$suffix"),
2022-03-17 11:41:04 +00:00
Pair(15f, "15$suffix"),
2021-11-30 17:59:52 +00:00
Pair(16f, "16$suffix"),
2022-03-17 11:41:04 +00:00
Pair(17f, "17$suffix"),
2021-11-30 17:59:52 +00:00
Pair(18f, "18$suffix"),
Pair(19f, "19$suffix"),
2022-03-17 11:41:04 +00:00
Pair(20f, "20$suffix"),
2021-11-30 17:59:52 +00:00
Pair(21f, "21$suffix"),
2022-03-17 11:41:04 +00:00
Pair(22f, "22$suffix"),
2021-11-30 17:59:52 +00:00
Pair(23f, "23$suffix"),
Pair(24f, "24$suffix"),
2022-03-17 11:41:04 +00:00
Pair(25f, "25$suffix"),
2021-11-30 17:59:52 +00:00
Pair(26f, "26$suffix"),
Pair(28f, "28$suffix"),
Pair(30f, "30$suffix"),
Pair(32f, "32$suffix"),
Pair(34f, "34$suffix"),
Pair(36f, "36$suffix"),
Pair(38f, "38$suffix"),
Pair(40f, "40$suffix"),
Pair(42f, "42$suffix"),
Pair(44f, "44$suffix"),
Pair(48f, "48$suffix"),
Pair(60f, "60$suffix"),
2021-09-16 12:46:21 +00:00
)
//showBottomDialog
2021-12-12 02:33:17 +00:00
activity?.showDialog(
2021-09-16 12:46:21 +00:00
fontSizes.map { it.second },
fontSizes.map { it.first }.indexOf(state.fixedTextSize),
(textView as TextView).text.toString(),
false,
dismissCallback
) { index ->
state.fixedTextSize = fontSizes.map { it.first }[index]
//textView.context.updateState() // font size not changed
}
}
subs_font_size.setOnLongClickListener { _ ->
state.fixedTextSize = null
//textView.context.updateState() // font size not changed
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true
}
2022-01-13 13:26:41 +00:00
subs_font.setFocusableInTv()
2021-08-07 01:53:45 +00:00
subs_font.setOnClickListener { textView ->
val fontTypes = listOf(
2021-11-30 17:59:52 +00:00
Pair(null, textView.context.getString(R.string.normal)),
2021-08-07 01:53:45 +00:00
Pair(R.font.trebuchet_ms, "Trebuchet MS"),
2021-11-20 15:19:24 +00:00
Pair(R.font.netflix_sans, "Netflix Sans"),
2021-08-07 01:53:45 +00:00
Pair(R.font.google_sans, "Google Sans"),
Pair(R.font.open_sans, "Open Sans"),
Pair(R.font.futura, "Futura"),
Pair(R.font.consola, "Consola"),
Pair(R.font.gotham, "Gotham"),
Pair(R.font.lucida_grande, "Lucida Grande"),
Pair(R.font.stix_general, "STIX General"),
Pair(R.font.times_new_roman, "Times New Roman"),
Pair(R.font.verdana, "Verdana"),
Pair(R.font.ubuntu_regular, "Ubuntu"),
2021-10-08 21:34:49 +00:00
Pair(R.font.comic_sans, "Comic Sans"),
2021-08-07 01:53:45 +00:00
Pair(R.font.poppins_regular, "Poppins"),
)
2022-04-16 23:03:18 +00:00
val savedFontTypes = textView.context.getSavedFonts()
val currentIndex =
savedFontTypes.indexOfFirst { it.absolutePath == state.typefaceFilePath }
.let { index ->
if (index == -1)
fontTypes.indexOfFirst { it.first == state.typeface }
else index + fontTypes.size
}
2021-08-07 01:53:45 +00:00
//showBottomDialog
2021-12-12 02:33:17 +00:00
activity?.showDialog(
2022-04-16 23:03:18 +00:00
fontTypes.map { it.second } + savedFontTypes.map { it.name },
currentIndex,
2021-08-07 01:53:45 +00:00
(textView as TextView).text.toString(),
false,
dismissCallback
) { index ->
2022-04-16 23:03:18 +00:00
if (index < fontTypes.size) {
state.typeface = fontTypes[index].first
state.typefaceFilePath = null
} else {
state.typefaceFilePath = savedFontTypes[index - fontTypes.size].absolutePath
state.typeface = null
}
2021-08-07 01:53:45 +00:00
textView.context.updateState()
}
}
subs_font.setOnLongClickListener { textView ->
2021-08-07 01:53:45 +00:00
state.typeface = null
2022-04-16 23:03:18 +00:00
state.typefaceFilePath = null
textView.context.updateState()
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true
}
2022-01-13 13:26:41 +00:00
subs_auto_select_language.setFocusableInTv()
subs_auto_select_language.setOnClickListener { textView ->
val langMap = arrayListOf(
2022-01-08 19:39:22 +00:00
SubtitleHelper.Language639(
textView.context.getString(R.string.none),
textView.context.getString(R.string.none),
"",
"",
"",
"",
""
),
)
langMap.addAll(SubtitleHelper.languages)
val lang639_1 = langMap.map { it.ISO_639_1 }
2021-12-12 02:33:17 +00:00
activity?.showDialog(
langMap.map { it.languageName },
lang639_1.indexOf(getAutoSelectLanguageISO639_1()),
(textView as TextView).text.toString(),
true,
dismissCallback
) { index ->
setKey(SUBTITLE_AUTO_SELECT_KEY, lang639_1[index])
}
}
subs_auto_select_language.setOnLongClickListener {
setKey(SUBTITLE_AUTO_SELECT_KEY, "en")
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
return@setOnLongClickListener true
}
2022-01-13 13:26:41 +00:00
subs_download_languages.setFocusableInTv()
subs_download_languages.setOnClickListener { textView ->
val langMap = SubtitleHelper.languages
val lang639_1 = langMap.map { it.ISO_639_1 }
val keys = getDownloadSubsLanguageISO639_1()
val keyMap = keys.map { lang639_1.indexOf(it) }.filter { it >= 0 }
2021-12-12 02:33:17 +00:00
activity?.showMultiDialog(
langMap.map { it.languageName },
keyMap,
(textView as TextView).text.toString(),
dismissCallback
) { indexList ->
setKey(SUBTITLE_DOWNLOAD_KEY, indexList.map { lang639_1[it] }.toList())
}
}
subs_download_languages.setOnLongClickListener {
setKey(SUBTITLE_DOWNLOAD_KEY, listOf("en"))
showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)
2021-08-06 20:55:11 +00:00
return@setOnLongClickListener true
}
cancel_btt.setOnClickListener {
activity?.popCurrentPage()
}
apply_btt.setOnClickListener {
2021-08-06 21:57:52 +00:00
it.context.saveStyle(state)
2021-08-06 20:55:11 +00:00
applyStyleEvent.invoke(state)
2021-08-07 01:53:45 +00:00
it.context.fromSaveToStyle(state)
2021-08-06 20:55:11 +00:00
activity?.popCurrentPage()
}
subtitle_text.setCues(
listOf(
Cue.Builder()
.setTextSize(
getPixels(TypedValue.COMPLEX_UNIT_SP, 25.0f).toFloat(),
Cue.TEXT_SIZE_TYPE_ABSOLUTE
)
2022-01-08 19:39:22 +00:00
.setText(subtitle_text.context.getString(R.string.subtitles_example_text))
.build()
2021-08-06 20:55:11 +00:00
)
)
}
2021-11-17 12:25:09 +00:00
}