Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
    pick 13699f6 Initial commit
    squash 7e8af2d Modify RichListDialog to display subtitle colors
    squash 19fcb15 Modify RichListOption to display subtitle colors

Modify RichListDialog to display subtitle colors

Modify RichListOption to display subtitle colors

Add subtitle options to preferences list

Add more subtitle options to preferences list

Final build, with all subtitle options added, and code analysis done to verify errors and warning are resolved

Update CONTRIBUTORS.md

added dark grey option and match master commit as much as possible

Fix line length

Fix line length

Fix API Level to Support 21 Lint Error 1

Fix API Level to Support 21 Lint Error 1

Fix API Level to Support 21 Lint Error 1

Fix API Level to Support 21 Lint Error 2

Update app/src/main/res/values/strings.xml

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/shared/StrokeTextView.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Requested resolutions implemented part 1

Update app/src/main/java/org/jellyfin/androidtv/ui/preference/dsl/OptionsColorList.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/shared/StrokeTextView.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Requested resolutions implemented part 2, restore RichListDialogFragment.kt and add ColorPickerDialogFragment and ColorListPreference

Requested resolutions implemented part 3, restore distributionkey

Rebased PlaybackPreferencesScreen.kt

Update app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/preference/dsl/OptionsColorList.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Resolve line length and magic number issues, using different background for the brighter colors

Update app/src/main/java/org/jellyfin/androidtv/ui/shared/StrokeTextView.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Resolve magic numbers attempt #2

Resolve magic numbers attempt 3

Resolve magic numbers attempt 4

Resolve line length issue

Remove unnecessary antialias

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/preference/screen/PlaybackPreferencesScreen.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Move subtitle setting preference to where the rest of the settings are located
Resolve formatting issue in PlaybackPreferenceScreen

Update PlaybackPreferencesScreen.kt

Fixing formatting

Move subtitle setting preference to where the rest of the settings are located
Resolve formatting issue in PlaybackPreferenceScreen
Resolve import of userpreferences in StrokeTextView.kt

Removed unnecessary functions and data attributes from ColorPickerDialogFragment.k

Update app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Update app/src/main/java/org/jellyfin/androidtv/ui/preference/screen/PlaybackPreferencesScreen.kt

Co-authored-by: Niels van Velzen <nielsvanvelzen@users.noreply.github.com>

Resolve magic numbers on lighter colors

Resolve positioning of subtitles and importing of preferences

Correct positioning of subtitlesTextColor in UserPreferences.kt
Lower Increment
  • Loading branch information
sparky3387 authored and s3397830 committed Oct 15, 2022
1 parent 962d56e commit b81538a
Show file tree
Hide file tree
Showing 15 changed files with 531 additions and 9 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [joern-h](https://github.com/joern-h)
- [Niels van Velzen](https://github.com/nielsvanvelzen)
- [GodTamIt](https://github.com/GodTamIt)
- [sparky3387](https://github.com/sparky3387)

# Emby Contributors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.jellyfin.androidtv.util.DeviceUtils
import org.jellyfin.preference.booleanPreference
import org.jellyfin.preference.enumPreference
import org.jellyfin.preference.intPreference
import org.jellyfin.preference.longPreference
import org.jellyfin.preference.migration.putEnum
import org.jellyfin.preference.store.SharedPreferenceStore
import org.jellyfin.preference.stringPreference
Expand Down Expand Up @@ -192,6 +193,21 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
* Set default subtitles font size
*/
var defaultSubtitlesSize = intPreference("subtitles_size", 28)

/**
* Set default subtitles stroke size
*/
var subtitleStrokeSize = intPreference("subtitles_stroke_size", 0)

/**
* Set default subtitles position
*/
var subtitlePosition = intPreference("subtitles_position", 40)

/**
* Foreground Color for the Subtitles
*/
var subtitlesTextColor = longPreference("subtitles_text_color", 0xFFFFFFFF)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.jellyfin.androidtv.ui.GuidePagingButton;
import org.jellyfin.androidtv.ui.HorizontalScrollViewListener;
import org.jellyfin.androidtv.ui.LiveProgramDetailPopup;

import org.jellyfin.androidtv.ui.ObservableHorizontalScrollView;
import org.jellyfin.androidtv.ui.ObservableScrollView;
import org.jellyfin.androidtv.ui.ProgramGridCell;
Expand Down Expand Up @@ -142,13 +143,16 @@ public class CustomPlaybackOverlayFragment extends Fragment implements LiveTvGui
private LeanbackOverlayFragment leanbackOverlayFragment;

// Subtitle fields
private static final int SUBTITLE_PADDING = 8;
private static final int SUBTITLE_PADDING = 20;
private static final long SUBTITLE_RENDER_INTERVAL_MS = 50;
private SubtitleTrackInfo subtitleTrackInfo;
private int currentSubtitleIndex = 0;
private int subtitlesSize = KoinJavaComponent.<UserPreferences>get(UserPreferences.class).get(UserPreferences.Companion.getDefaultSubtitlesSize());
private long lastSubtitlePositionMs = 0;
private boolean subtitlesBackgroundEnabled = KoinJavaComponent.<UserPreferences>get(UserPreferences.class).get(UserPreferences.Companion.getSubtitlesBackgroundEnabled());
private final UserPreferences userPreferences = KoinJavaComponent.<UserPreferences>get(UserPreferences.class);
private final int subtitlesSize = userPreferences.get(UserPreferences.Companion.getDefaultSubtitlesSize());
private final boolean subtitlesBackgroundEnabled = userPreferences.get(UserPreferences.Companion.getSubtitlesBackgroundEnabled());
private final int subtitlesPosition = userPreferences.get(UserPreferences.Companion.getSubtitlePosition());
private final int subtitlesStrokeWidth = userPreferences.get(UserPreferences.Companion.getSubtitleStrokeSize());

private final Lazy<ApiClient> apiClient = inject(ApiClient.class);
private final Lazy<org.jellyfin.sdk.api.client.ApiClient> api = inject(org.jellyfin.sdk.api.client.ApiClient.class);
Expand Down Expand Up @@ -257,6 +261,18 @@ public void onActivityCreated(Bundle savedInstanceState) {
// Subtitles font size configuration
binding.subtitlesText.setTextSize(subtitlesSize);

// Subtitles font position (margin bottom)
if (subtitlesPosition > 0) {
ViewGroup.MarginLayoutParams currentLayoutParams = (ViewGroup.MarginLayoutParams)binding.subtitlesText.getLayoutParams();
currentLayoutParams.bottomMargin = (8 + Utils.convertDpToPixel(requireContext(), subtitlesPosition));
binding.subtitlesText.setLayoutParams(currentLayoutParams);
}

// Subtitles stroke width
if (subtitlesStrokeWidth > 0 && !subtitlesBackgroundEnabled) {
binding.subtitlesText.setStrokeWidth(subtitlesStrokeWidth);
}

//pre-load animations
fadeOut = AnimationUtils.loadAnimation(requireContext(), R.anim.abc_fade_out);
fadeOut.setAnimationListener(hideAnimationListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
import org.jellyfin.androidtv.ui.preference.custom.ButtonRemapDialogFragment
import org.jellyfin.androidtv.ui.preference.custom.ButtonRemapPreference
import org.jellyfin.androidtv.ui.preference.custom.ColorListPreference
import org.jellyfin.androidtv.ui.preference.custom.ColorPickerDialogFragment
import org.jellyfin.androidtv.ui.preference.custom.RichListDialogFragment
import org.jellyfin.androidtv.ui.preference.custom.RichListPreference
import timber.log.Timber

class PreferencesFragment : LeanbackSettingsFragmentCompat() {
override fun onPreferenceStartInitialScreen() {
Expand Down Expand Up @@ -45,6 +48,7 @@ class PreferencesFragment : LeanbackSettingsFragmentCompat() {
// Custom
is ButtonRemapPreference -> ButtonRemapDialogFragment.newInstance(pref.key)
is RichListPreference<*> -> RichListDialogFragment.newInstance(pref.key)
is ColorListPreference<*> -> ColorPickerDialogFragment.newInstance(pref.key)
is ListPreference -> RichListDialogFragment.newInstance(pref.key)

// Leanback
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.jellyfin.androidtv.ui.preference.custom

import android.content.Context
import android.util.AttributeSet
import androidx.preference.ListPreference
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.ui.preference.custom.ColorPickerDialogFragment.ColorListItem
import org.jellyfin.androidtv.ui.preference.custom.ColorPickerDialogFragment.ColorListItem.ColorListOption

class ColorListPreference<String> @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle,
defStyleRes: Int = 0,
) : ListPreference(context, attrs, defStyleAttr, defStyleRes) {
private var items: List<ColorListItem<String>> = emptyList()
var value: String? = null

fun setItems(items: Map<Long, String>) {
this.items = items.entries.map {
ColorListOption(it.key, it.value.toString())
}
}

fun getItems(): List<ColorListItem<String>> = items
fun getOptions(): List<ColorListOption<String>> = getItems().filterIsInstance<ColorListOption<String>>()
fun getItem(key: String) = getOptions().firstOrNull { it.key.toString() == key }
fun getCurrentItem() = value?.let(::getItem)

class SimpleSummaryProvider : SummaryProvider<ColorListPreference<*>> {
override fun provideSummary(preference: ColorListPreference<*>) =
preference.getCurrentItem()?.title ?: preference.context.getString(R.string.not_set)

companion object {
val instance by lazy { SimpleSummaryProvider() }
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package org.jellyfin.androidtv.ui.preference.custom

import android.content.res.ColorStateList
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Checkable
import android.widget.RadioButton
import android.widget.TextView
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
import androidx.leanback.preference.LeanbackPreferenceDialogFragmentCompat
import androidx.leanback.widget.VerticalGridView
import androidx.preference.ListPreference
import androidx.recyclerview.widget.RecyclerView
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.databinding.PreferenceColorListBinding

class ColorPickerDialogFragment : LeanbackPreferenceDialogFragmentCompat() {
companion object {
fun newInstance(key: String) = ColorPickerDialogFragment().apply {
arguments = Bundle().apply {
putString(ARG_KEY, key)
}
}
}

@Suppress("MagicNumber")
private val lighterYellow: Long = 0xFFEEDC00
@Suppress("MagicNumber")
private val lighterWhite: Long = 0xFFEEDC00

private lateinit var binding: PreferenceColorListBinding
private lateinit var adapter: RecyclerView.Adapter<*>

private fun <K> ColorListPreference<K>.createAdapter() = Adapter(
items = getItems(),
selectedValue = value
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = when (val preference = preference) {
// Adapt ListPreference to ColorListItems
is ColorListPreference<*> -> preference.createAdapter()
else -> throw NotImplementedError()
}
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val styledContext = ContextThemeWrapper(activity, R.style.PreferenceThemeOverlayLeanback)
val styledInflater = inflater.cloneInContext(styledContext)
binding = PreferenceColorListBinding.inflate(styledInflater, container, false)

// Dialog
binding.decorTitle.text = preference.dialogTitle

if (preference.dialogMessage?.isNotBlank() == true) {
binding.message.text = preference.dialogMessage
binding.message.isVisible = true
}

// Items
val verticalGridView = binding.list
verticalGridView.windowAlignment = VerticalGridView.WINDOW_ALIGN_BOTH_EDGE
verticalGridView.adapter = adapter
verticalGridView.requestFocus()

return binding.root
}

/**
* Items used in [Adapter].
*/
sealed class ColorListItem<K> {
data class ColorListOption<K>(
val key: Long,
val title: String,
val summary: String? = null
) : ColorListItem<K>()
}

inner class Adapter<K>(
private val items: List<ColorListItem<K>>,
private var selectedValue: K? = null,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemCount() = items.size

override fun getItemViewType(position: Int) = when (items[position]) {
is ColorListItem.ColorListOption<*> -> R.layout.preference_color_list_option
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(viewType, parent, false)
return when (viewType) {
R.layout.preference_color_list_option -> OptionViewHolder(view, ::onItemClick)
else -> throw NotImplementedError()
}
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) = when (val item = items[position]) {

is ColorListItem.ColorListOption<*> -> {
holder as OptionViewHolder
holder.button.isChecked = item.key.toString() == selectedValue

var buttontint: Int
if (holder.button.isChecked) {
buttontint =
if (item.key == lighterWhite ||
item.key == lighterYellow) R.color.button_default_disabled_text
else R.color.button_default_normal_text
} else {
buttontint = R.color.transparent
}
holder.buttonbg.background = context?.let{ResourcesCompat.getDrawable(
it.resources,R.drawable.subtitle_background,it.theme)}
holder.buttonfg.backgroundTintList = ColorStateList.valueOf(item.key.toString().toLong().toInt())
holder.buttontint.buttonTintList =
context?.let { context ->
ContextCompat.getColor(context, buttontint).let {
ColorStateList.valueOf(it)
}
}
holder.title.text = item.title
holder.summary.text = item.summary
holder.summary.isVisible = item.summary?.isNotBlank() == true
}
}

fun onItemClick(viewHolder: OptionViewHolder) {
val index = viewHolder.absoluteAdapterPosition
if (index == RecyclerView.NO_POSITION) return

val item = items[index] as ColorListItem.ColorListOption<K>
if (preference.callChangeListener(item.key)) {
when (val preference = preference) {
is ListPreference -> preference.value = item.key as String
}

selectedValue = item.key as K
}

parentFragmentManager.popBackStack()
notifyDataSetChanged()
}
}

class OptionViewHolder(
view: View,
private val clickListener: (viewHolder: OptionViewHolder) -> Unit
) : RecyclerView.ViewHolder(view), View.OnClickListener {
var buttonbg: View = view.findViewById(R.id.button)
var buttonfg: View = view.findViewById(R.id.button)
var buttontint: RadioButton = view.findViewById(R.id.button)
val button = view.findViewById(R.id.button) as Checkable
val title: TextView = view.findViewById(R.id.title)
val summary: TextView = view.findViewById(R.id.summary)
val container: ViewGroup = view.findViewById<ViewGroup>(R.id.container).also {
it.setOnClickListener(this)
}

override fun onClick(view: View) = clickListener(this)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.jellyfin.androidtv.ui.preference.dsl

import android.content.Context
import androidx.annotation.StringRes
import androidx.preference.PreferenceCategory
import org.jellyfin.androidtv.ui.preference.custom.ColorListPreference
import java.util.UUID

class OptionsColorList(
private val context: Context
) : OptionsItemMutable<Long>() {
var entries: Map<Long, String> = emptyMap()

fun setTitle(@StringRes resId: Int) {
title = context.getString(resId)
}

override fun build(category: PreferenceCategory, container: OptionsUpdateFunContainer) {
val pref = ColorListPreference<String>(context).also {
it.isPersistent = false
it.key = UUID.randomUUID().toString()
category.addPreference(it)
it.isEnabled = dependencyCheckFun() && enabled
it.isVisible = visible
it.title = title
it.dialogTitle = title
it.summaryProvider = ColorListPreference.SimpleSummaryProvider.instance
it.setItems(entries)
it.entryValues = entries.keys.map { longitems -> longitems.toString() }.toTypedArray()
it.entries = entries.values.toTypedArray()
it.value = binder.get().toString()
it.setOnPreferenceChangeListener { _, newValue ->
binder.set(newValue.toString().toLong())
it.value = binder.get().toString()
container()

// Always return false because we save it
false
}
}

container += {
pref.isEnabled = dependencyCheckFun() && enabled
}
}
}

@OptionsDSL
fun OptionsCategory.colorList(init: OptionsColorList.() -> Unit) {
this += OptionsColorList(context).apply { init() }
}
Loading

0 comments on commit b81538a

Please sign in to comment.