Custom SponsorBlock segment colors option (#4055)

Co-authored-by: Bnyro <bnyro@tutanota.com>
This commit is contained in:
general-a 2023-06-22 08:31:41 -05:00 committed by GitHub
parent 332978a100
commit 2e56db0219
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 402 additions and 9 deletions

View File

@ -2,6 +2,7 @@ package com.github.libretube.enums
enum class SbSkipOptions {
OFF,
VISIBLE,
MANUAL,
AUTOMATIC
}

View File

@ -451,7 +451,7 @@ object PlayerHelper {
}
}
seekTo(segmentEnd)
} else {
} else if (sponsorBlockConfig[segment.category] == SbSkipOptions.MANUAL) {
return segmentEnd
}
}

View File

@ -0,0 +1,130 @@
package com.github.libretube.ui.dialogs
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.widget.SeekBar
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import com.github.libretube.R
import com.github.libretube.databinding.DialogColorPickerBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class ColorPickerDialog(
private val context: Context,
private val initialColor: Int,
private val onColorSelectedListener: OnColorSelectedListener
) : DialogFragment(), SeekBar.OnSeekBarChangeListener {
private var _binding: DialogColorPickerBinding? = null
private val binding get() = _binding!!
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
_binding = DialogColorPickerBinding.inflate(layoutInflater)
// Set initial color
setColor(initialColor)
binding.alphaSeekBar.setOnSeekBarChangeListener(this)
binding.redSeekBar.setOnSeekBarChangeListener(this)
binding.greenSeekBar.setOnSeekBarChangeListener(this)
binding.blueSeekBar.setOnSeekBarChangeListener(this)
// Add listener to text input
binding.colorHexInput.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int,
after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int,
count: Int) = Unit
var isValid = true
var oldHex = ""
override fun afterTextChanged(s: Editable?) {
// Update color when text input changes
val hexColor = s.toString()
if (hexColor.length == 9 && oldHex != hexColor) {
isValid = try {
oldHex = hexColor
val color = Color.parseColor(hexColor)
setColor(color, true)
true
} catch (e: IllegalArgumentException) {
if (isValid) {
showInvalidColorMessage()
}
false
}
}
}
})
return MaterialAlertDialogBuilder(requireContext())
.setView(binding.root)
.setPositiveButton(R.string.okay) { _, _ ->
onColorSelectedListener.onColorSelected(getColor())
}
.setNegativeButton(R.string.cancel, null)
.show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
// Update color preview when SeekBar progress changes
setColorPreview(getColor())
}
override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit
override fun onStopTrackingTouch(seekBar: SeekBar?) {
val newColorString = colorToString(getColor())
if (newColorString != binding.colorHexInput.text.toString()) {
binding.colorHexInput.setText(newColorString)
}
}
private fun showInvalidColorMessage() {
Toast.makeText(context, R.string.invalid_color, Toast.LENGTH_SHORT).show()
}
// Get the color from the SeekBar progress values
private fun getColor() = Color.argb(binding.alphaSeekBar.progress, binding.redSeekBar.progress,
binding.greenSeekBar.progress, binding.blueSeekBar.progress)
private fun setColor(color: Int, textUpdate: Boolean = false) {
// Set the SeekBar progress values based on the color
binding.alphaSeekBar.progress = Color.alpha(color)
binding.redSeekBar.progress = Color.red(color)
binding.greenSeekBar.progress = Color.green(color)
binding.blueSeekBar.progress = Color.blue(color)
// Set the hex color input value
if (!textUpdate) {
binding.colorHexInput.setText(colorToString(color))
}
binding.colorPreview.setBackgroundColor(color)
}
private fun setColorPreview(color: Int) {
// Set the color preview
binding.colorPreview.setBackgroundColor(color)
}
private fun colorToString(color: Int): String {
return String.format("#%08X", color)
}
fun interface OnColorSelectedListener {
fun onColorSelected(color: Int)
}
}

View File

@ -672,7 +672,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
}
return
}
}
private fun playVideo() {

View File

@ -0,0 +1,74 @@
package com.github.libretube.ui.views
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import com.github.libretube.R
import com.github.libretube.ui.dialogs.ColorPickerDialog
class ColorPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
private lateinit var circleView: View
private var currentColor: Int? = null
init {
layoutResource = R.layout.color_preference
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
holder.itemView.findViewById<TextView>(android.R.id.title)?.text = title
circleView = holder.itemView.findViewById(R.id.circle)
updateColorView()
holder.itemView.setOnClickListener {
showColorPickerDialog()
}
}
private fun setColor(color: Int) {
currentColor = color
persistInt(color)
updateColorView()
}
override fun onGetDefaultValue(ta: TypedArray, index: Int): Any {
return Color.parseColor(ta.getString(index))
}
override fun onSetInitialValue(defaultValue: Any?) {
val color = if (defaultValue is Int) {
getPersistedInt(defaultValue)
} else {
getPersistedInt(Color.WHITE)
}
currentColor = color
persistInt(color)
}
private fun updateColorView() {
(if (currentColor is Int) currentColor else Color.WHITE)?.let {
circleView.setBackgroundColor(it)
}
}
private fun showColorPickerDialog() {
(if (currentColor is Int) currentColor else Color.BLACK)?.let {
val dialog = ColorPickerDialog(context, it) { color -> setColor(color) }
dialog.show((context as AppCompatActivity).supportFragmentManager, this::class.java.name)
}
}
override fun getTitle(): CharSequence? {
return "${super.getTitle()}:"
}
}

View File

@ -45,6 +45,7 @@ class MarkableTimeBar(
val horizontalOffset = (parent as View).marginLeft
length = canvas.width - horizontalOffset * 2
val marginY = canvas.height / 2 - progressBarHeight / 2
val themeColor = ThemeHelper.getThemeColor(context, R.attr.colorOnSecondary,)
segments.forEach {
canvas.drawRect(
@ -55,10 +56,11 @@ class MarkableTimeBar(
canvas.height - marginY,
),
Paint().apply {
color = ThemeHelper.getThemeColor(
context,
R.attr.colorOnSecondary,
)
color = if (PreferenceHelper.getBoolean("sb_enable_custom_colors", false)) {
PreferenceHelper.getInt(it.category + "_color", themeColor)
} else {
themeColor
}
},
)
}

View File

@ -0,0 +1,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#000" />
</shape>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingTop="10dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingBottom="10dp">
<TextView
android:id="@android:id/title"
style="?android:attr/preferenceStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:layout_weight="1"
android:ellipsize="end"
android:fadingEdge="horizontal"
android:singleLine="true"
android:text="Title"
android:textAlignment="textEnd"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="14sp"
android:textStyle="italic" />
<View
android:id="@+id/circle"
android:layout_width="20sp"
android:layout_height="20sp"
android:layout_alignParentEnd="true"
android:background="@drawable/circle"
android:layout_marginStart="16dp"/>
</LinearLayout>

View File

@ -0,0 +1,92 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:paddingHorizontal="20dp"
android:paddingTop="30dp">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginVertical="10dp"
app:cardCornerRadius="10dp">
<View
android:id="@+id/colorPreview"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#000000" />
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="R"
tools:ignore="HardcodedText" />
<SeekBar
android:id="@+id/redSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:max="255"
android:progress="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="G"
tools:ignore="HardcodedText" />
<SeekBar
android:id="@+id/greenSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:max="255"
android:progress="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
tools:ignore="HardcodedText" />
<SeekBar
android:id="@+id/blueSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:max="255"
android:progress="0" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
tools:ignore="HardcodedText" />
<SeekBar
android:id="@+id/alphaSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="5dp"
android:max="255"
android:progress="255" />
<EditText
android:id="@+id/colorHexInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp"
android:hint="#00000000"
tools:ignore="HardcodedText" />
</LinearLayout>

View File

@ -424,12 +424,14 @@
<string-array name="sb_skip_options">
<item>@string/off</item>
<item>@string/visible</item>
<item>@string/manual</item>
<item>@string/automatic</item>
</string-array>
<string-array name="sb_skip_options_values">
<item>off</item>
<item>visible</item>
<item>manual</item>
<item>automatic</item>
</string-array>

View File

@ -303,6 +303,11 @@
<string name="queue">Queue</string>
<string name="sb_markers">Markers</string>
<string name="sb_markers_summary">Mark the segments on the time bar.</string>
<string name="sb_color_enable">Toggles custom color segments for sponsor block segments</string>
<string name="sb_custom_colors">Custom segment colors</string>
<string name="color">Color</string>
<string name="invalid_color">Invalid color value entered!</string>
<string name="enter_hex_value">Enter Color Hex Value</string>
<string name="livestreams">Livestreams</string>
<string name="alternative_videos_layout">Alternative videos layout</string>
<string name="defaultIconLight">Default light</string>
@ -419,9 +424,10 @@
<string name="change_playlist_description">Change playlist description</string>
<string name="playlist_description">Playlist description</string>
<string name="emptyPlaylistDescription">The playlist description can\'t be empty</string>
<string name="off">Off</string>
<string name="manual">Manual</string>
<string name="automatic">Automatic</string>
<string name="off">Disable</string>
<string name="visible">Show in seek bar</string>
<string name="manual">Manual skip</string>
<string name="automatic">Auto skip</string>
<!-- Backup & Restore Settings -->
<string name="import_subscriptions_from">Import subscriptions from</string>

View File

@ -24,6 +24,12 @@
app:key="sb_show_markers"
app:title="@string/sb_markers" />
<SwitchPreferenceCompat
android:summary="@string/sb_color_enable"
app:defaultValue="false"
android:dependency="sb_enabled_key"
app:key="sb_enable_custom_colors"
app:title="@string/sb_custom_colors" />
<PreferenceCategory app:title="@string/category_segments">
@ -33,6 +39,10 @@
app:title="@string/category_sponsor"
app:defaultValue="automatic"/>
<com.github.libretube.ui.views.ColorPreference
app:key="sponsor_color"
app:title="@string/color"
app:defaultValue="#00d400" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="selfpromo_category"
@ -40,42 +50,77 @@
app:title="@string/category_selfpromo"
app:defaultValue="automatic"/>
<com.github.libretube.ui.views.ColorPreference
app:key="selfpromo_color"
app:title="@string/color"
app:defaultValue="#ffff00" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="interaction_category"
app:summary="@string/category_interaction_description"
app:title="@string/category_interaction"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="interaction_color"
app:title="@string/color"
app:defaultValue="#cc00ff" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="intro_category"
app:summary="@string/category_intro_description"
app:title="@string/category_intro"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="intro_color"
app:title="@string/color"
app:defaultValue="#00ffff" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="outro_category"
app:summary="@string/category_outro_description"
app:title="@string/category_outro"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="outro_color"
app:title="@string/color"
app:defaultValue="#0202ED" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="filler_category"
app:summary="@string/category_filler_description"
app:title="@string/category_filler"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="filler_color"
app:title="@string/color"
app:defaultValue="#7300ff" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="music_offtopic_category"
app:summary="@string/category_music_offtopic_description"
app:title="@string/category_music_offtopic"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="music_offtopic_color"
app:title="@string/color"
app:defaultValue="#ff9900" />
<com.github.libretube.ui.views.SbSpinnerPreference
app:key="preview_category"
app:summary="@string/category_preview_description"
app:title="@string/category_preview"
app:defaultValue="off"/>
<com.github.libretube.ui.views.ColorPreference
app:key="preview_color"
app:title="@string/color"
app:defaultValue="#008fd6" />
</PreferenceCategory>
</PreferenceScreen>