mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-07-04 02:53:09 +00:00
Implementation of player settings page in Settings page redesign
- Added new files for the Fragment and xml related to the player settings page. - Implemented the player settings page per the description in https://github.com/TeamNewPipe/NewPipe/issues/9587. - These changes facilitate easier switching between current and new behaviors. - They also lay the groundwork for easier cleanup when the new design is approved and enabled by default. Video: - https://github.com/TeamNewPipe/NewPipe/assets/87667048/00385bbb-6a2f-4ce5-b6b9-6cf1cb5c5636
This commit is contained in:
parent
89645fab99
commit
5ca85861e7
@ -0,0 +1,211 @@
|
|||||||
|
package org.schabi.newpipe.settings
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
|
import android.content.res.Resources.NotFoundException
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import org.schabi.newpipe.R
|
||||||
|
import org.schabi.newpipe.util.ListHelper
|
||||||
|
import org.schabi.newpipe.util.PermissionHelper
|
||||||
|
import java.util.LinkedList
|
||||||
|
|
||||||
|
class PlayerSettingsFragment : BasePreferenceFragment() {
|
||||||
|
private lateinit var listener: OnSharedPreferenceChangeListener
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
addPreferencesFromResourceRegistry()
|
||||||
|
updateSeekOptions()
|
||||||
|
updateResolutionOptions()
|
||||||
|
listener = OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||||
|
// on M and above, if user chooses to minimise to popup player on exit and the app
|
||||||
|
// doesn't have display over other apps permission, show a snack bar to let the user
|
||||||
|
// give permission
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||||
|
getString(R.string.minimize_on_exit_key) == key
|
||||||
|
) {
|
||||||
|
sharedPreferences.getString(key, null)
|
||||||
|
?.takeIf {
|
||||||
|
getString(R.string.minimize_on_exit_popup_key) == it &&
|
||||||
|
!Settings.canDrawOverlays(context)
|
||||||
|
}?.let {
|
||||||
|
Snackbar.make(
|
||||||
|
listView,
|
||||||
|
R.string.permission_display_over_apps,
|
||||||
|
Snackbar.LENGTH_INDEFINITE,
|
||||||
|
).setAction(R.string.settings) {
|
||||||
|
PermissionHelper.checkSystemAlertWindowPermission(context)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
} else if (getString(R.string.use_inexact_seek_key) == key) {
|
||||||
|
updateSeekOptions()
|
||||||
|
} else if (getString(R.string.show_higher_resolutions_key) == key) {
|
||||||
|
updateResolutionOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update default resolution, default popup resolution & mobile data resolution options.
|
||||||
|
* <br></br>
|
||||||
|
* Show high resolutions when "Show higher resolution" option is enabled.
|
||||||
|
* Set default resolution to "best resolution" when "Show higher resolution" option
|
||||||
|
* is disabled.
|
||||||
|
*/
|
||||||
|
private fun updateResolutionOptions() {
|
||||||
|
val resources = resources
|
||||||
|
val showHigherResolutions = preferenceManager.getSharedPreferences()
|
||||||
|
?.getBoolean(resources.getString(R.string.show_higher_resolutions_key), false) ?: false
|
||||||
|
|
||||||
|
// get sorted resolution lists
|
||||||
|
val resolutionListDescriptions = ListHelper.getSortedResolutionList(
|
||||||
|
resources,
|
||||||
|
R.array.resolution_list_description,
|
||||||
|
R.array.high_resolution_list_descriptions,
|
||||||
|
showHigherResolutions,
|
||||||
|
)
|
||||||
|
val resolutionListValues = ListHelper.getSortedResolutionList(
|
||||||
|
resources,
|
||||||
|
R.array.resolution_list_values,
|
||||||
|
R.array.high_resolution_list_values,
|
||||||
|
showHigherResolutions,
|
||||||
|
)
|
||||||
|
val limitDataUsageResolutionValues = ListHelper.getSortedResolutionList(
|
||||||
|
resources,
|
||||||
|
R.array.limit_data_usage_values_list,
|
||||||
|
R.array.high_resolution_limit_data_usage_values_list,
|
||||||
|
showHigherResolutions,
|
||||||
|
)
|
||||||
|
val limitDataUsageResolutionDescriptions = ListHelper
|
||||||
|
.getSortedResolutionList(
|
||||||
|
resources,
|
||||||
|
R.array.limit_data_usage_description_list,
|
||||||
|
R.array.high_resolution_list_descriptions,
|
||||||
|
showHigherResolutions,
|
||||||
|
)
|
||||||
|
|
||||||
|
// get resolution preferences
|
||||||
|
val defaultResolution = findPreference<ListPreference>(
|
||||||
|
getString(R.string.default_resolution_key)
|
||||||
|
)
|
||||||
|
val defaultPopupResolution = findPreference<ListPreference>(
|
||||||
|
getString(R.string.default_popup_resolution_key)
|
||||||
|
)
|
||||||
|
val mobileDataResolution = findPreference<ListPreference>(
|
||||||
|
getString(R.string.limit_mobile_data_usage_key)
|
||||||
|
)
|
||||||
|
|
||||||
|
// update resolution preferences with new resolutions, entries & values for each
|
||||||
|
defaultResolution?.entries = resolutionListDescriptions.toTypedArray<String>()
|
||||||
|
defaultResolution?.entryValues = resolutionListValues.toTypedArray<String>()
|
||||||
|
defaultPopupResolution?.entries = resolutionListDescriptions.toTypedArray<String>()
|
||||||
|
defaultPopupResolution?.entryValues = resolutionListValues.toTypedArray<String>()
|
||||||
|
mobileDataResolution?.entries = limitDataUsageResolutionDescriptions.toTypedArray<String>()
|
||||||
|
mobileDataResolution?.entryValues =
|
||||||
|
limitDataUsageResolutionValues.toTypedArray<String>()
|
||||||
|
|
||||||
|
// if "Show higher resolution" option is disabled,
|
||||||
|
// set default resolution to "best resolution"
|
||||||
|
if (!showHigherResolutions) {
|
||||||
|
if (defaultResolution != null && ListHelper.isHighResolutionSelected(
|
||||||
|
defaultResolution.value,
|
||||||
|
R.array.high_resolution_list_values,
|
||||||
|
resources
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
defaultResolution.setValueIndex(0)
|
||||||
|
}
|
||||||
|
if (defaultPopupResolution != null && ListHelper.isHighResolutionSelected(
|
||||||
|
defaultPopupResolution.value,
|
||||||
|
R.array.high_resolution_list_values,
|
||||||
|
resources,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
defaultPopupResolution.setValueIndex(0)
|
||||||
|
}
|
||||||
|
if (mobileDataResolution != null && ListHelper.isHighResolutionSelected(
|
||||||
|
mobileDataResolution.value,
|
||||||
|
R.array.high_resolution_limit_data_usage_values_list,
|
||||||
|
resources,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
mobileDataResolution.setValueIndex(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update fast-forward/-rewind seek duration options
|
||||||
|
* according to language and inexact seek setting.
|
||||||
|
* Exoplayer can't seek 5 seconds in audio when using inexact seek.
|
||||||
|
*/
|
||||||
|
private fun updateSeekOptions() {
|
||||||
|
// initializing R.array.seek_duration_description to display the translation of seconds
|
||||||
|
val durationsValues = resources.getStringArray(R.array.seek_duration_value)
|
||||||
|
val displayedDurationValues = LinkedList<String>()
|
||||||
|
val displayedDescriptionValues = LinkedList<String>()
|
||||||
|
val inexactSeek = preferenceManager.getSharedPreferences()
|
||||||
|
?.getBoolean(resources.getString(R.string.use_inexact_seek_key), false) ?: false
|
||||||
|
for (durationsValue in durationsValues) {
|
||||||
|
val currentDurationValue = durationsValue.toInt() / DateUtils.SECOND_IN_MILLIS.toInt()
|
||||||
|
if (inexactSeek && currentDurationValue % 10 == 5) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
displayedDurationValues.add(durationsValue)
|
||||||
|
try {
|
||||||
|
displayedDescriptionValues.add(
|
||||||
|
String.format(
|
||||||
|
resources.getQuantityString(R.plurals.seconds, currentDurationValue),
|
||||||
|
currentDurationValue
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} catch (ignored: NotFoundException) {
|
||||||
|
// if this happens, the translation is missing,
|
||||||
|
// and the english string will be displayed instead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
findPreference<ListPreference>(getString(R.string.seek_duration_key))?.apply {
|
||||||
|
entryValues = displayedDurationValues.toTypedArray<CharSequence>()
|
||||||
|
entries = displayedDescriptionValues.toTypedArray<CharSequence>()
|
||||||
|
val selectedDuration = value.toLong()
|
||||||
|
if (inexactSeek && selectedDuration / DateUtils.SECOND_IN_MILLIS % 10 == 5L) {
|
||||||
|
val newDuration = selectedDuration / DateUtils.SECOND_IN_MILLIS + 5
|
||||||
|
value = (newDuration * DateUtils.SECOND_IN_MILLIS).toString()
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
getString(R.string.new_seek_duration_toast, newDuration),
|
||||||
|
Toast.LENGTH_LONG,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
preferenceManager.getSharedPreferences()?.registerOnSharedPreferenceChangeListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
preferenceManager.getSharedPreferences()?.unregisterOnSharedPreferenceChangeListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||||
|
if (getString(R.string.caption_settings_key) == preference.key) {
|
||||||
|
try {
|
||||||
|
startActivity(Intent(Settings.ACTION_CAPTIONING_SETTINGS))
|
||||||
|
} catch (error: ActivityNotFoundException) {
|
||||||
|
Toast.makeText(requireContext(), R.string.general_error, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onPreferenceTreeClick(preference)
|
||||||
|
}
|
||||||
|
}
|
@ -30,11 +30,11 @@ public final class SettingsResourceRegistry {
|
|||||||
|
|
||||||
private SettingsResourceRegistry() {
|
private SettingsResourceRegistry() {
|
||||||
add(MainSettingsV2Fragment.class, R.xml.main_settings_v2).setSearchable(false);
|
add(MainSettingsV2Fragment.class, R.xml.main_settings_v2).setSearchable(false);
|
||||||
|
add(PlayerSettingsFragment.class, R.xml.player_settings);
|
||||||
|
|
||||||
// Before redesign settings arrangement. These should be cleared once the
|
// Before redesign settings arrangement. These should be cleared once the
|
||||||
// settings_layout_redesign_key is approved and enabled by default.
|
// settings_layout_redesign_key is approved and enabled by default.
|
||||||
add(MainSettingsFragment.class, R.xml.main_settings).setSearchable(false);
|
add(MainSettingsFragment.class, R.xml.main_settings).setSearchable(false);
|
||||||
|
|
||||||
add(AppearanceSettingsFragment.class, R.xml.appearance_settings);
|
add(AppearanceSettingsFragment.class, R.xml.appearance_settings);
|
||||||
add(ContentSettingsFragment.class, R.xml.content_settings);
|
add(ContentSettingsFragment.class, R.xml.content_settings);
|
||||||
add(DebugSettingsFragment.class, R.xml.debug_settings).setSearchable(false);
|
add(DebugSettingsFragment.class, R.xml.debug_settings).setSearchable(false);
|
||||||
|
@ -846,4 +846,6 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="show_more">Show more</string>
|
<string name="show_more">Show more</string>
|
||||||
<string name="show_less">Show less</string>
|
<string name="show_less">Show less</string>
|
||||||
|
<!-- Settings redesign -->
|
||||||
|
<string name="settings_category_resolution_and_format_title">Resolution and format</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
android:key="general_preferences"
|
android:key="general_preferences"
|
||||||
android:title="@string/settings">
|
android:title="@string/settings">
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:fragment="org.schabi.newpipe.settings.PlayerSettingsFragment"
|
||||||
|
android:title="@string/settings_category_player_title"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:fragment="org.schabi.newpipe.settings.DebugSettingsFragment"
|
android:fragment="org.schabi.newpipe.settings.DebugSettingsFragment"
|
||||||
android:key="@string/debug_pref_screen_key"
|
android:key="@string/debug_pref_screen_key"
|
||||||
|
150
app/src/main/res/xml/player_settings.xml
Normal file
150
app/src/main/res/xml/player_settings.xml
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:title="@string/settings_category_player_title">
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/settings_category_header_layout"
|
||||||
|
android:title="@string/settings_category_resolution_and_format_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false">
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/default_resolution_value"
|
||||||
|
android:entries="@array/resolution_list_description"
|
||||||
|
android:entryValues="@array/resolution_list_values"
|
||||||
|
android:key="@string/default_resolution_key"
|
||||||
|
android:title="@string/default_resolution_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/default_popup_resolution_value"
|
||||||
|
android:entries="@array/resolution_list_description"
|
||||||
|
android:entryValues="@array/resolution_list_values"
|
||||||
|
android:key="@string/default_popup_resolution_key"
|
||||||
|
android:title="@string/default_popup_resolution_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/limit_mobile_data_usage_value"
|
||||||
|
android:entries="@array/limit_data_usage_description_list"
|
||||||
|
android:entryValues="@array/limit_data_usage_values_list"
|
||||||
|
android:key="@string/limit_mobile_data_usage_key"
|
||||||
|
android:title="@string/limit_mobile_data_usage_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/show_higher_resolutions_key"
|
||||||
|
android:summary="@string/show_higher_resolutions_summary"
|
||||||
|
android:title="@string/show_higher_resolutions_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/default_video_format_value"
|
||||||
|
android:entries="@array/video_format_description_list"
|
||||||
|
android:entryValues="@array/video_format_values_list"
|
||||||
|
android:key="@string/default_video_format_key"
|
||||||
|
android:title="@string/default_video_format_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:defaultValue="@string/default_audio_format_value"
|
||||||
|
android:entries="@array/audio_format_description_list"
|
||||||
|
android:entryValues="@array/audio_format_values_list"
|
||||||
|
android:key="@string/default_audio_format_key"
|
||||||
|
android:title="@string/default_audio_format_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/prefer_original_audio_key"
|
||||||
|
android:summary="@string/prefer_original_audio_summary"
|
||||||
|
android:title="@string/prefer_original_audio_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/prefer_descriptive_audio_key"
|
||||||
|
android:summary="@string/prefer_descriptive_audio_summary"
|
||||||
|
android:title="@string/prefer_descriptive_audio_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:fragment="org.schabi.newpipe.settings.ExoPlayerSettingsFragment"
|
||||||
|
android:key="@string/exoplayer_settings_key"
|
||||||
|
android:summary="@string/settings_category_exoplayer_summary"
|
||||||
|
android:title="@string/settings_category_exoplayer_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:layout="@layout/settings_category_header_layout"
|
||||||
|
android:title="@string/settings_category_player_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false">
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/use_external_video_player_key"
|
||||||
|
android:summary="@string/use_external_video_player_summary"
|
||||||
|
android:title="@string/use_external_video_player_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/use_external_audio_player_key"
|
||||||
|
android:title="@string/use_external_audio_player_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="@string/show_play_with_kodi_key"
|
||||||
|
android:summary="@string/show_play_with_kodi_summary"
|
||||||
|
android:title="@string/show_play_with_kodi_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:defaultValue="seekbar_preview_thumbnail_high_quality"
|
||||||
|
android:entries="@array/seekbar_preview_thumbnail_type_description"
|
||||||
|
android:entryValues="@array/seekbar_preview_thumbnail_type_key"
|
||||||
|
android:key="@string/seekbar_preview_thumbnail_key"
|
||||||
|
android:title="@string/seekbar_preview_thumbnail_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="@string/caption_settings_key"
|
||||||
|
android:summary="@string/caption_setting_description"
|
||||||
|
android:title="@string/caption_setting_title"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="@string/player_notification_screen_key"
|
||||||
|
android:summary="@string/settings_category_player_notification_summary"
|
||||||
|
android:title="@string/settings_category_player_notification_title"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:singleLineTitle="false" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
</PreferenceScreen>
|
Loading…
x
Reference in New Issue
Block a user