From 2e771cd65ab1eff2cb090351a4083d1d129fe53a Mon Sep 17 00:00:00 2001 From: GGAutomaton <32899400+GGAutomaton@users.noreply.github.com> Date: Mon, 4 Apr 2022 23:58:39 +0800 Subject: [PATCH 001/106] Fix crash when rotating device on unsupported channels --- .../fragments/list/channel/ChannelFragment.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 869503b5b..6ad811320 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -77,6 +77,8 @@ public class ChannelFragment extends BaseListInfoFragment Date: Thu, 14 Apr 2022 22:08:42 -0400 Subject: [PATCH 002/106] Update ACRA library --- app/build.gradle | 2 +- app/src/main/java/org/schabi/newpipe/App.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 95d1c98af..c0489e384 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -262,7 +262,7 @@ dependencies { implementation "com.nononsenseapps:filepicker:4.2.1" // Crash reporting - implementation "ch.acra:acra-core:5.8.4" + implementation "ch.acra:acra-core:5.9.1" // Properly restarting implementation 'com.jakewharton:process-phoenix:2.1.2' diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 6b02e21ca..70c947478 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -205,7 +205,7 @@ public class App extends MultiDexApplication { return; } - final CoreConfigurationBuilder acraConfig = new CoreConfigurationBuilder(this) + final CoreConfigurationBuilder acraConfig = new CoreConfigurationBuilder() .withBuildConfigClass(BuildConfig.class); ACRA.init(this, acraConfig); } From 652d50173e64efd01eeca1c9454d205c2c513b4a Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 1 Jan 2022 19:02:03 +0100 Subject: [PATCH 003/106] Major refactoring of PlaybackParameterDialog * Removed/Renamed methods * Use ``IcePick`` * Better structuring * Keep skipSilence when rotating the device (PlayQueueActivity only) --- .../helper/PlaybackParameterDialog.java | 726 ++++++------------ 1 file changed, 224 insertions(+), 502 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 1a55c21c3..b72b7ea7b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -9,10 +9,10 @@ import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.CheckBox; -import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.TextView; +import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; @@ -20,104 +20,88 @@ import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; -import org.schabi.newpipe.util.SimpleOnSeekBarChangeListener; import org.schabi.newpipe.util.SliderStrategy; +import java.util.Objects; +import java.util.function.DoubleConsumer; +import java.util.function.DoubleFunction; + +import icepick.Icepick; +import icepick.State; + public class PlaybackParameterDialog extends DialogFragment { + private static final String TAG = "PlaybackParameterDialog"; + // Minimum allowable range in ExoPlayer private static final double MINIMUM_PLAYBACK_VALUE = 0.10f; private static final double MAXIMUM_PLAYBACK_VALUE = 3.00f; - private static final char STEP_UP_SIGN = '+'; - private static final char STEP_DOWN_SIGN = '-'; - - private static final double STEP_ONE_PERCENT_VALUE = 0.01f; - private static final double STEP_FIVE_PERCENT_VALUE = 0.05f; - private static final double STEP_TEN_PERCENT_VALUE = 0.10f; - private static final double STEP_TWENTY_FIVE_PERCENT_VALUE = 0.25f; - private static final double STEP_ONE_HUNDRED_PERCENT_VALUE = 1.00f; + private static final double STEP_1_PERCENT_VALUE = 0.01f; + private static final double STEP_5_PERCENT_VALUE = 0.05f; + private static final double STEP_10_PERCENT_VALUE = 0.10f; + private static final double STEP_25_PERCENT_VALUE = 0.25f; + private static final double STEP_100_PERCENT_VALUE = 1.00f; private static final double DEFAULT_TEMPO = 1.00f; private static final double DEFAULT_PITCH = 1.00f; - private static final int DEFAULT_SEMITONES = 0; - private static final double DEFAULT_STEP = STEP_TWENTY_FIVE_PERCENT_VALUE; + private static final double DEFAULT_STEP = STEP_25_PERCENT_VALUE; private static final boolean DEFAULT_SKIP_SILENCE = false; - @NonNull - private static final String TAG = "PlaybackParameterDialog"; - @NonNull - private static final String INITIAL_TEMPO_KEY = "initial_tempo_key"; - @NonNull - private static final String INITIAL_PITCH_KEY = "initial_pitch_key"; - - @NonNull - private static final String TEMPO_KEY = "tempo_key"; - @NonNull - private static final String PITCH_KEY = "pitch_key"; - @NonNull - private static final String STEP_SIZE_KEY = "step_size_key"; - - @NonNull - private final SliderStrategy strategy = new SliderStrategy.Quadratic( - MINIMUM_PLAYBACK_VALUE, MAXIMUM_PLAYBACK_VALUE, - /*centerAt=*/1.00f, /*sliderGranularity=*/10000); + private static final SliderStrategy QUADRATIC_STRATEGY = new SliderStrategy.Quadratic( + MINIMUM_PLAYBACK_VALUE, + MAXIMUM_PLAYBACK_VALUE, + 1.00f, + 10_000); @Nullable private Callback callback; - private double initialTempo = DEFAULT_TEMPO; - private double initialPitch = DEFAULT_PITCH; - private int initialSemitones = DEFAULT_SEMITONES; - private boolean initialSkipSilence = DEFAULT_SKIP_SILENCE; - private double tempo = DEFAULT_TEMPO; - private double pitch = DEFAULT_PITCH; - private int semitones = DEFAULT_SEMITONES; + @State + double initialTempo = DEFAULT_TEMPO; + @State + double initialPitch = DEFAULT_PITCH; + @State + boolean initialSkipSilence = DEFAULT_SKIP_SILENCE; + + @State + double tempo = DEFAULT_TEMPO; + @State + double pitch = DEFAULT_PITCH; + @State + double stepSize = DEFAULT_STEP; + @State + boolean skipSilence = DEFAULT_SKIP_SILENCE; - @Nullable private SeekBar tempoSlider; - @Nullable private TextView tempoCurrentText; - @Nullable private TextView tempoStepDownText; - @Nullable private TextView tempoStepUpText; - @Nullable - private SeekBar pitchSlider; - @Nullable - private TextView pitchCurrentText; - @Nullable - private TextView pitchStepDownText; - @Nullable - private TextView pitchStepUpText; - @Nullable - private SeekBar semitoneSlider; - @Nullable - private TextView semitoneCurrentText; - @Nullable - private TextView semitoneStepDownText; - @Nullable - private TextView semitoneStepUpText; - @Nullable - private CheckBox unhookingCheckbox; - @Nullable - private CheckBox skipSilenceCheckbox; - @Nullable - private CheckBox adjustBySemitonesCheckbox; - public static PlaybackParameterDialog newInstance(final double playbackTempo, - final double playbackPitch, - final boolean playbackSkipSilence, - final Callback callback) { + private SeekBar pitchSlider; + private TextView pitchCurrentText; + private TextView pitchStepDownText; + private TextView pitchStepUpText; + + private CheckBox unhookingCheckbox; + private CheckBox skipSilenceCheckbox; + + public static PlaybackParameterDialog newInstance( + final double playbackTempo, + final double playbackPitch, + final boolean playbackSkipSilence, + final Callback callback + ) { final PlaybackParameterDialog dialog = new PlaybackParameterDialog(); dialog.callback = callback; + dialog.initialTempo = playbackTempo; dialog.initialPitch = playbackPitch; - - dialog.tempo = playbackTempo; - dialog.pitch = playbackPitch; - dialog.semitones = dialog.percentToSemitones(playbackPitch); - dialog.initialSkipSilence = playbackSkipSilence; + + dialog.tempo = dialog.initialTempo; + dialog.pitch = dialog.initialPitch; + dialog.skipSilence = dialog.initialSkipSilence; + return dialog; } @@ -126,7 +110,7 @@ public class PlaybackParameterDialog extends DialogFragment { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(@NonNull final Context context) { + public void onAttach(final Context context) { super.onAttach(context); if (context instanceof Callback) { callback = (Callback) context; @@ -136,28 +120,9 @@ public class PlaybackParameterDialog extends DialogFragment { } @Override - public void onCreate(@Nullable final Bundle savedInstanceState) { - assureCorrectAppLanguage(getContext()); - super.onCreate(savedInstanceState); - if (savedInstanceState != null) { - initialTempo = savedInstanceState.getDouble(INITIAL_TEMPO_KEY, DEFAULT_TEMPO); - initialPitch = savedInstanceState.getDouble(INITIAL_PITCH_KEY, DEFAULT_PITCH); - initialSemitones = percentToSemitones(initialPitch); - - tempo = savedInstanceState.getDouble(TEMPO_KEY, DEFAULT_TEMPO); - pitch = savedInstanceState.getDouble(PITCH_KEY, DEFAULT_PITCH); - semitones = percentToSemitones(pitch); - } - } - - @Override - public void onSaveInstanceState(@NonNull final Bundle outState) { + public void onSaveInstanceState(final Bundle outState) { super.onSaveInstanceState(outState); - outState.putDouble(INITIAL_TEMPO_KEY, initialTempo); - outState.putDouble(INITIAL_PITCH_KEY, initialPitch); - - outState.putDouble(TEMPO_KEY, getCurrentTempo()); - outState.putDouble(PITCH_KEY, getCurrentPitch()); + Icepick.saveInstanceState(this, outState); } /*////////////////////////////////////////////////////////////////////////// @@ -168,20 +133,28 @@ public class PlaybackParameterDialog extends DialogFragment { @Override public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) { assureCorrectAppLanguage(getContext()); + Icepick.restoreInstanceState(this, savedInstanceState); + final View view = View.inflate(getContext(), R.layout.dialog_playback_parameter, null); - setupControlViews(view); + initUI(view); + initUIData(); final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity()) .setView(view) .setCancelable(true) - .setNegativeButton(R.string.cancel, (dialogInterface, i) -> - setPlaybackParameters(initialTempo, initialPitch, - initialSemitones, initialSkipSilence)) - .setNeutralButton(R.string.playback_reset, (dialogInterface, i) -> - setPlaybackParameters(DEFAULT_TEMPO, DEFAULT_PITCH, - DEFAULT_SEMITONES, DEFAULT_SKIP_SILENCE)) - .setPositiveButton(R.string.ok, (dialogInterface, i) -> - setCurrentPlaybackParameters()); + .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { + setAndUpdateTempo(initialTempo); + setAndUpdatePitch(initialPitch); + setAndUpdateSkipSilence(initialSkipSilence); + updateCallback(); + }) + .setNeutralButton(R.string.playback_reset, (dialogInterface, i) -> { + setAndUpdateTempo(DEFAULT_TEMPO); + setAndUpdatePitch(DEFAULT_PITCH); + setAndUpdateSkipSilence(DEFAULT_SKIP_SILENCE); + updateCallback(); + }) + .setPositiveButton(R.string.ok, (dialogInterface, i) -> updateCallback()); return dialogBuilder.create(); } @@ -190,353 +163,171 @@ public class PlaybackParameterDialog extends DialogFragment { // Control Views //////////////////////////////////////////////////////////////////////////*/ - private void setupControlViews(@NonNull final View rootView) { - setupHookingControl(rootView); - setupSkipSilenceControl(rootView); - setupAdjustBySemitonesControl(rootView); + private void initUI(@NonNull final View rootView) { + // Tempo + tempoSlider = Objects.requireNonNull(rootView.findViewById(R.id.tempoSeekbar)); + tempoCurrentText = Objects.requireNonNull(rootView.findViewById(R.id.tempoCurrentText)); + tempoStepUpText = Objects.requireNonNull(rootView.findViewById(R.id.tempoStepUp)); + tempoStepDownText = Objects.requireNonNull(rootView.findViewById(R.id.tempoStepDown)); - setupTempoControl(rootView); - setupPitchControl(rootView); - setupSemitoneControl(rootView); + setText(rootView, R.id.tempoMinimumText, PlayerHelper::formatSpeed, MINIMUM_PLAYBACK_VALUE); + setText(rootView, R.id.tempoMaximumText, PlayerHelper::formatSpeed, MAXIMUM_PLAYBACK_VALUE); - togglePitchSliderType(rootView); + // Pitch + pitchSlider = Objects.requireNonNull(rootView.findViewById(R.id.pitchSeekbar)); + pitchCurrentText = Objects.requireNonNull(rootView.findViewById(R.id.pitchCurrentText)); + pitchStepUpText = Objects.requireNonNull(rootView.findViewById(R.id.pitchStepUp)); + pitchStepDownText = Objects.requireNonNull(rootView.findViewById(R.id.pitchStepDown)); - setupStepSizeSelector(rootView); + setText(rootView, R.id.pitchMinimumText, PlayerHelper::formatPitch, MINIMUM_PLAYBACK_VALUE); + setText(rootView, R.id.pitchMaximumText, PlayerHelper::formatPitch, MAXIMUM_PLAYBACK_VALUE); + + // Steps + setupStepTextView(rootView, R.id.stepSizeOnePercent, STEP_1_PERCENT_VALUE); + setupStepTextView(rootView, R.id.stepSizeFivePercent, STEP_5_PERCENT_VALUE); + setupStepTextView(rootView, R.id.stepSizeTenPercent, STEP_10_PERCENT_VALUE); + setupStepTextView(rootView, R.id.stepSizeTwentyFivePercent, STEP_25_PERCENT_VALUE); + setupStepTextView(rootView, R.id.stepSizeOneHundredPercent, STEP_100_PERCENT_VALUE); + + // Bottom controls + unhookingCheckbox = + Objects.requireNonNull(rootView.findViewById(R.id.unhookCheckbox)); + skipSilenceCheckbox = + Objects.requireNonNull(rootView.findViewById(R.id.skipSilenceCheckbox)); } - private void togglePitchSliderType(@NonNull final View rootView) { - final RelativeLayout pitchControl = rootView.findViewById(R.id.pitchControl); - final RelativeLayout semitoneControl = rootView.findViewById(R.id.semitoneControl); - - final View separatorStepSizeSelector = - rootView.findViewById(R.id.separatorStepSizeSelector); - final RelativeLayout.LayoutParams params = - (RelativeLayout.LayoutParams) separatorStepSizeSelector.getLayoutParams(); - if (pitchControl != null && semitoneControl != null && unhookingCheckbox != null) { - if (getCurrentAdjustBySemitones()) { - // replaces pitchControl slider with semitoneControl slider - pitchControl.setVisibility(View.GONE); - semitoneControl.setVisibility(View.VISIBLE); - params.addRule(RelativeLayout.BELOW, R.id.semitoneControl); - - // forces unhook for semitones - unhookingCheckbox.setChecked(true); - unhookingCheckbox.setEnabled(false); - - setupTempoStepSizeSelector(rootView); - } else { - semitoneControl.setVisibility(View.GONE); - pitchControl.setVisibility(View.VISIBLE); - params.addRule(RelativeLayout.BELOW, R.id.pitchControl); - - // (re)enables hooking selection - unhookingCheckbox.setEnabled(true); - setupCombinedStepSizeSelector(rootView); - } - } + private TextView setText( + final TextView textView, + final DoubleFunction formatter, + final double value + ) { + Objects.requireNonNull(textView).setText(formatter.apply(value)); + return textView; } - private void setupTempoControl(@NonNull final View rootView) { - tempoSlider = rootView.findViewById(R.id.tempoSeekbar); - final TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText); - final TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText); - tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText); - tempoStepUpText = rootView.findViewById(R.id.tempoStepUp); - tempoStepDownText = rootView.findViewById(R.id.tempoStepDown); - - if (tempoCurrentText != null) { - tempoCurrentText.setText(PlayerHelper.formatSpeed(tempo)); - } - if (tempoMaximumText != null) { - tempoMaximumText.setText(PlayerHelper.formatSpeed(MAXIMUM_PLAYBACK_VALUE)); - } - if (tempoMinimumText != null) { - tempoMinimumText.setText(PlayerHelper.formatSpeed(MINIMUM_PLAYBACK_VALUE)); - } - - if (tempoSlider != null) { - tempoSlider.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); - tempoSlider.setProgress(strategy.progressOf(tempo)); - tempoSlider.setOnSeekBarChangeListener(getOnTempoChangedListener()); - } + private TextView setText( + final View rootView, + @IdRes final int idRes, + final DoubleFunction formatter, + final double value + ) { + final TextView textView = rootView.findViewById(idRes); + setText(textView, formatter, value); + return textView; } - private void setupPitchControl(@NonNull final View rootView) { - pitchSlider = rootView.findViewById(R.id.pitchSeekbar); - final TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText); - final TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText); - pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText); - pitchStepDownText = rootView.findViewById(R.id.pitchStepDown); - pitchStepUpText = rootView.findViewById(R.id.pitchStepUp); - - if (pitchCurrentText != null) { - pitchCurrentText.setText(PlayerHelper.formatPitch(pitch)); - } - if (pitchMaximumText != null) { - pitchMaximumText.setText(PlayerHelper.formatPitch(MAXIMUM_PLAYBACK_VALUE)); - } - if (pitchMinimumText != null) { - pitchMinimumText.setText(PlayerHelper.formatPitch(MINIMUM_PLAYBACK_VALUE)); - } - - if (pitchSlider != null) { - pitchSlider.setMax(strategy.progressOf(MAXIMUM_PLAYBACK_VALUE)); - pitchSlider.setProgress(strategy.progressOf(pitch)); - pitchSlider.setOnSeekBarChangeListener(getOnPitchChangedListener()); - } + private void setupStepTextView( + final View rootView, + @IdRes final int idRes, + final double stepSizeValue + ) { + setText(rootView, idRes, PlaybackParameterDialog::getPercentString, stepSizeValue) + .setOnClickListener(view -> setAndUpdateStepSize(stepSizeValue)); } - private void setupSemitoneControl(@NonNull final View rootView) { - semitoneSlider = rootView.findViewById(R.id.semitoneSeekbar); - semitoneCurrentText = rootView.findViewById(R.id.semitoneCurrentText); - semitoneStepDownText = rootView.findViewById(R.id.semitoneStepDown); - semitoneStepUpText = rootView.findViewById(R.id.semitoneStepUp); + private void initUIData() { + // Tempo + tempoSlider.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); + setAndUpdateTempo(tempo); + tempoSlider.setOnSeekBarChangeListener( + getTempoOrPitchSeekbarChangeListener(this::onTempoSliderUpdated)); - if (semitoneCurrentText != null) { - semitoneCurrentText.setText(getSignedSemitonesString(semitones)); - } + registerOnStepClickListener( + tempoStepDownText, tempo, -1, this::onTempoSliderUpdated); + registerOnStepClickListener( + tempoStepUpText, tempo, 1, this::onTempoSliderUpdated); - if (semitoneSlider != null) { - setSemitoneSlider(semitones); - semitoneSlider.setOnSeekBarChangeListener(getOnSemitoneChangedListener()); - } + // Pitch + pitchSlider.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); + setAndUpdatePitch(pitch); + pitchSlider.setOnSeekBarChangeListener( + getTempoOrPitchSeekbarChangeListener(this::onPitchSliderUpdated)); - } + registerOnStepClickListener( + pitchStepDownText, pitch, -1, this::onPitchSliderUpdated); + registerOnStepClickListener( + pitchStepUpText, pitch, 1, this::onPitchSliderUpdated); - private void setupHookingControl(@NonNull final View rootView) { - unhookingCheckbox = rootView.findViewById(R.id.unhookCheckbox); - if (unhookingCheckbox != null) { - // restores whether pitch and tempo are unhooked or not - unhookingCheckbox.setChecked(PreferenceManager - .getDefaultSharedPreferences(requireContext()) - .getBoolean(getString(R.string.playback_unhook_key), true)); + // Steps + setAndUpdateStepSize(stepSize); - unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { - // saves whether pitch and tempo are unhooked or not - PreferenceManager.getDefaultSharedPreferences(requireContext()) - .edit() - .putBoolean(getString(R.string.playback_unhook_key), isChecked) - .apply(); - - if (!isChecked) { - // when unchecked, slides back to the minimum of current tempo or pitch - final double minimum = Math.min(getCurrentPitch(), getCurrentTempo()); - setSliders(minimum); - setCurrentPlaybackParameters(); - } - }); - } - } - - private void setupSkipSilenceControl(@NonNull final View rootView) { - skipSilenceCheckbox = rootView.findViewById(R.id.skipSilenceCheckbox); - if (skipSilenceCheckbox != null) { - skipSilenceCheckbox.setChecked(initialSkipSilence); - skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> - setCurrentPlaybackParameters()); - } - } - - private void setupAdjustBySemitonesControl(@NonNull final View rootView) { - adjustBySemitonesCheckbox = rootView.findViewById(R.id.adjustBySemitonesCheckbox); - if (adjustBySemitonesCheckbox != null) { - // restores whether semitone adjustment is used or not - adjustBySemitonesCheckbox.setChecked(PreferenceManager + // Bottom controls + // restore whether pitch and tempo are unhooked or not + unhookingCheckbox.setChecked(PreferenceManager .getDefaultSharedPreferences(requireContext()) - .getBoolean(getString(R.string.playback_adjust_by_semitones_key), true)); + .getBoolean(getString(R.string.playback_unhook_key), true)); - // stores whether semitone adjustment is used or not - adjustBySemitonesCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { - PreferenceManager.getDefaultSharedPreferences(requireContext()) + unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + // save whether pitch and tempo are unhooked or not + PreferenceManager.getDefaultSharedPreferences(requireContext()) .edit() - .putBoolean(getString(R.string.playback_adjust_by_semitones_key), isChecked) + .putBoolean(getString(R.string.playback_unhook_key), isChecked) .apply(); - togglePitchSliderType(rootView); - if (isChecked) { - setPlaybackParameters( - getCurrentTempo(), - getCurrentPitch(), - Integer.min(12, - Integer.max(-12, percentToSemitones(getCurrentPitch()) - )), - getCurrentSkipSilence() - ); - setSemitoneSlider(Integer.min(12, - Integer.max(-12, percentToSemitones(getCurrentPitch())) - )); - } else { - setPlaybackParameters( - getCurrentTempo(), - semitonesToPercent(getCurrentSemitones()), - getCurrentSemitones(), - getCurrentSkipSilence() - ); - setPitchSlider(semitonesToPercent(getCurrentSemitones())); - } - }); - } + + if (!isChecked) { + // when unchecked, slide back to the minimum of current tempo or pitch + setSliders(Math.min(pitch, tempo)); + } + }); + + setAndUpdateSkipSilence(skipSilence); + skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + skipSilence = isChecked; + updateCallback(); + }); } - private void setupStepSizeSelector(@NonNull final View rootView) { - setStepSize(PreferenceManager - .getDefaultSharedPreferences(requireContext()) - .getFloat(getString(R.string.adjustment_step_key), (float) DEFAULT_STEP)); - - final TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent); - final TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent); - final TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent); - final TextView stepSizeTwentyFivePercentText = rootView - .findViewById(R.id.stepSizeTwentyFivePercent); - final TextView stepSizeOneHundredPercentText = rootView - .findViewById(R.id.stepSizeOneHundredPercent); - - if (stepSizeOnePercentText != null) { - stepSizeOnePercentText.setText(getPercentString(STEP_ONE_PERCENT_VALUE)); - stepSizeOnePercentText - .setOnClickListener(view -> setStepSize(STEP_ONE_PERCENT_VALUE)); - } - - if (stepSizeFivePercentText != null) { - stepSizeFivePercentText.setText(getPercentString(STEP_FIVE_PERCENT_VALUE)); - stepSizeFivePercentText - .setOnClickListener(view -> setStepSize(STEP_FIVE_PERCENT_VALUE)); - } - - if (stepSizeTenPercentText != null) { - stepSizeTenPercentText.setText(getPercentString(STEP_TEN_PERCENT_VALUE)); - stepSizeTenPercentText - .setOnClickListener(view -> setStepSize(STEP_TEN_PERCENT_VALUE)); - } - - if (stepSizeTwentyFivePercentText != null) { - stepSizeTwentyFivePercentText - .setText(getPercentString(STEP_TWENTY_FIVE_PERCENT_VALUE)); - stepSizeTwentyFivePercentText - .setOnClickListener(view -> setStepSize(STEP_TWENTY_FIVE_PERCENT_VALUE)); - } - - if (stepSizeOneHundredPercentText != null) { - stepSizeOneHundredPercentText - .setText(getPercentString(STEP_ONE_HUNDRED_PERCENT_VALUE)); - stepSizeOneHundredPercentText - .setOnClickListener(view -> setStepSize(STEP_ONE_HUNDRED_PERCENT_VALUE)); - } + private void registerOnStepClickListener( + final TextView stepTextView, + final double currentValue, + final double direction, // -1 for step down, +1 for step up + final DoubleConsumer newValueConsumer + ) { + stepTextView.setOnClickListener(view -> + newValueConsumer.accept(currentValue * direction) + ); } - private void setupTempoStepSizeSelector(@NonNull final View rootView) { - final TextView playbackStepTypeText = rootView.findViewById(R.id.playback_step_type); - if (playbackStepTypeText != null) { - playbackStepTypeText.setText(R.string.playback_tempo_step); - } - setupStepSizeSelector(rootView); + private void setAndUpdateStepSize(final double newStepSize) { + this.stepSize = newStepSize; + + tempoStepUpText.setText(getStepUpPercentString(newStepSize)); + tempoStepDownText.setText(getStepDownPercentString(newStepSize)); + + pitchStepUpText.setText(getStepUpPercentString(newStepSize)); + pitchStepDownText.setText(getStepDownPercentString(newStepSize)); } - private void setupCombinedStepSizeSelector(@NonNull final View rootView) { - final TextView playbackStepTypeText = rootView.findViewById(R.id.playback_step_type); - if (playbackStepTypeText != null) { - playbackStepTypeText.setText(R.string.playback_step); - } - setupStepSizeSelector(rootView); - } - - private void setStepSize(final double stepSize) { - PreferenceManager.getDefaultSharedPreferences(requireContext()) - .edit() - .putFloat(getString(R.string.adjustment_step_key), (float) stepSize) - .apply(); - - if (tempoStepUpText != null) { - tempoStepUpText.setText(getStepUpPercentString(stepSize)); - tempoStepUpText.setOnClickListener(view -> { - onTempoSliderUpdated(getCurrentTempo() + stepSize); - setCurrentPlaybackParameters(); - }); - } - - if (tempoStepDownText != null) { - tempoStepDownText.setText(getStepDownPercentString(stepSize)); - tempoStepDownText.setOnClickListener(view -> { - onTempoSliderUpdated(getCurrentTempo() - stepSize); - setCurrentPlaybackParameters(); - }); - } - - if (pitchStepUpText != null) { - pitchStepUpText.setText(getStepUpPercentString(stepSize)); - pitchStepUpText.setOnClickListener(view -> { - onPitchSliderUpdated(getCurrentPitch() + stepSize); - setCurrentPlaybackParameters(); - }); - } - - if (pitchStepDownText != null) { - pitchStepDownText.setText(getStepDownPercentString(stepSize)); - pitchStepDownText.setOnClickListener(view -> { - onPitchSliderUpdated(getCurrentPitch() - stepSize); - setCurrentPlaybackParameters(); - }); - } - - if (semitoneStepDownText != null) { - semitoneStepDownText.setOnClickListener(view -> { - onSemitoneSliderUpdated(getCurrentSemitones() - 1); - setCurrentPlaybackParameters(); - }); - } - - if (semitoneStepUpText != null) { - semitoneStepUpText.setOnClickListener(view -> { - onSemitoneSliderUpdated(getCurrentSemitones() + 1); - setCurrentPlaybackParameters(); - }); - } + private void setAndUpdateSkipSilence(final boolean newSkipSilence) { + this.skipSilence = newSkipSilence; + skipSilenceCheckbox.setChecked(newSkipSilence); } /*////////////////////////////////////////////////////////////////////////// // Sliders //////////////////////////////////////////////////////////////////////////*/ - private SimpleOnSeekBarChangeListener getOnTempoChangedListener() { - return new SimpleOnSeekBarChangeListener() { + private SeekBar.OnSeekBarChangeListener getTempoOrPitchSeekbarChangeListener( + final DoubleConsumer newValueConsumer + ) { + return new SeekBar.OnSeekBarChangeListener() { @Override - public void onProgressChanged(@NonNull final SeekBar seekBar, final int progress, + public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) { - final double currentTempo = strategy.valueOf(progress); - if (fromUser) { - onTempoSliderUpdated(currentTempo); - setCurrentPlaybackParameters(); + if (fromUser) { // this change is first in chain + newValueConsumer.accept(QUADRATIC_STRATEGY.valueOf(progress)); + updateCallback(); } } - }; - } - private SimpleOnSeekBarChangeListener getOnPitchChangedListener() { - return new SimpleOnSeekBarChangeListener() { @Override - public void onProgressChanged(@NonNull final SeekBar seekBar, final int progress, - final boolean fromUser) { - final double currentPitch = strategy.valueOf(progress); - if (fromUser) { // this change is first in chain - onPitchSliderUpdated(currentPitch); - setCurrentPlaybackParameters(); - } + public void onStartTrackingTouch(final SeekBar seekBar) { + // Do nothing } - }; - } - private SimpleOnSeekBarChangeListener getOnSemitoneChangedListener() { - return new SimpleOnSeekBarChangeListener() { @Override - public void onProgressChanged(@NonNull final SeekBar seekBar, final int progress, - final boolean fromUser) { - // semitone slider supplies values 0 to 24, subtraction by 12 is required - final int currentSemitones = progress - 12; - if (fromUser) { // this change is first in chain - onSemitoneSliderUpdated(currentSemitones); - // line below also saves semitones as pitch percentages - onPitchSliderUpdated(semitonesToPercent(currentSemitones)); - setCurrentPlaybackParameters(); - } + public void onStopTrackingTouch(final SeekBar seekBar) { + // Do nothing } }; } @@ -545,7 +336,7 @@ public class PlaybackParameterDialog extends DialogFragment { if (!unhookingCheckbox.isChecked()) { setSliders(newTempo); } else { - setTempoSlider(newTempo); + setAndUpdateTempo(newTempo); } } @@ -553,109 +344,53 @@ public class PlaybackParameterDialog extends DialogFragment { if (!unhookingCheckbox.isChecked()) { setSliders(newPitch); } else { - setPitchSlider(newPitch); + setAndUpdatePitch(newPitch); } } - private void onSemitoneSliderUpdated(final int newSemitone) { - setSemitoneSlider(newSemitone); - } - private void setSliders(final double newValue) { - setTempoSlider(newValue); - setPitchSlider(newValue); + setAndUpdateTempo(newValue); + setAndUpdatePitch(newValue); } - private void setTempoSlider(final double newTempo) { - if (tempoSlider == null) { - return; - } - tempoSlider.setProgress(strategy.progressOf(newTempo)); + private void setAndUpdateTempo(final double newTempo) { + this.tempo = newTempo; + tempoSlider.setProgress(QUADRATIC_STRATEGY.progressOf(tempo)); + setText(tempoCurrentText, PlayerHelper::formatSpeed, tempo); } - private void setPitchSlider(final double newPitch) { - if (pitchSlider == null) { - return; - } - pitchSlider.setProgress(strategy.progressOf(newPitch)); - } - - private void setSemitoneSlider(final int newSemitone) { - if (semitoneSlider == null) { - return; - } - semitoneSlider.setProgress(newSemitone + 12); + private void setAndUpdatePitch(final double newPitch) { + this.pitch = newPitch; + pitchSlider.setProgress(QUADRATIC_STRATEGY.progressOf(pitch)); + setText(pitchCurrentText, PlayerHelper::formatPitch, pitch); } /*////////////////////////////////////////////////////////////////////////// // Helper //////////////////////////////////////////////////////////////////////////*/ - private void setCurrentPlaybackParameters() { - if (getCurrentAdjustBySemitones()) { - setPlaybackParameters( - getCurrentTempo(), - semitonesToPercent(getCurrentSemitones()), - getCurrentSemitones(), - getCurrentSkipSilence() - ); - } else { - setPlaybackParameters( - getCurrentTempo(), - getCurrentPitch(), - percentToSemitones(getCurrentPitch()), - getCurrentSkipSilence() + private void updateCallback() { + if (callback == null) { + return; + } + if (DEBUG) { + Log.d(TAG, "Updating callback: " + + "tempo = [" + tempo + "], " + + "pitch = [" + pitch + "], " + + "skipSilence = [" + skipSilence + "]" ); } - } - - private void setPlaybackParameters(final double newTempo, final double newPitch, - final int newSemitones, final boolean skipSilence) { - if (callback != null && tempoCurrentText != null - && pitchCurrentText != null && semitoneCurrentText != null) { - if (DEBUG) { - Log.d(TAG, "Setting playback parameters to " - + "tempo=[" + newTempo + "], " - + "pitch=[" + newPitch + "], " - + "semitones=[" + newSemitones + "]"); - } - - tempoCurrentText.setText(PlayerHelper.formatSpeed(newTempo)); - pitchCurrentText.setText(PlayerHelper.formatPitch(newPitch)); - semitoneCurrentText.setText(getSignedSemitonesString(newSemitones)); - callback.onPlaybackParameterChanged((float) newTempo, (float) newPitch, skipSilence); - } - } - - private double getCurrentTempo() { - return tempoSlider == null ? tempo : strategy.valueOf(tempoSlider.getProgress()); - } - - private double getCurrentPitch() { - return pitchSlider == null ? pitch : strategy.valueOf(pitchSlider.getProgress()); - } - - private int getCurrentSemitones() { - // semitoneSlider is absolute, that's why - 12 - return semitoneSlider == null ? semitones : semitoneSlider.getProgress() - 12; - } - - private boolean getCurrentSkipSilence() { - return skipSilenceCheckbox != null && skipSilenceCheckbox.isChecked(); - } - - private boolean getCurrentAdjustBySemitones() { - return adjustBySemitonesCheckbox != null && adjustBySemitonesCheckbox.isChecked(); + callback.onPlaybackParameterChanged((float) tempo, (float) pitch, skipSilence); } @NonNull private static String getStepUpPercentString(final double percent) { - return STEP_UP_SIGN + getPercentString(percent); + return '+' + getPercentString(percent); } @NonNull private static String getStepDownPercentString(final double percent) { - return STEP_DOWN_SIGN + getPercentString(percent); + return '-' + getPercentString(percent); } @NonNull @@ -663,21 +398,8 @@ public class PlaybackParameterDialog extends DialogFragment { return PlayerHelper.formatPitch(percent); } - @NonNull - private static String getSignedSemitonesString(final int semitones) { - return semitones > 0 ? "+" + semitones : "" + semitones; - } - public interface Callback { void onPlaybackParameterChanged(float playbackTempo, float playbackPitch, boolean playbackSkipSilence); } - - public double semitonesToPercent(final int inSemitones) { - return Math.pow(2, inSemitones / 12.0); - } - - public int percentToSemitones(final double inPercent) { - return (int) Math.round(12 * Math.log(inPercent) / Math.log(2)); - } } From 4cdf6eda2cf3d9073d9ccad7c339bfb1856189c2 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Mon, 28 Feb 2022 20:45:23 +0100 Subject: [PATCH 004/106] Use viewbinding --- .../helper/PlaybackParameterDialog.java | 124 ++++++------------ 1 file changed, 42 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index b72b7ea7b..e1874fec0 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -7,12 +7,10 @@ import android.app.Dialog; import android.content.Context; import android.os.Bundle; import android.util.Log; -import android.view.View; -import android.widget.CheckBox; +import android.view.LayoutInflater; import android.widget.SeekBar; import android.widget.TextView; -import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; @@ -20,6 +18,7 @@ import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; +import org.schabi.newpipe.databinding.DialogPlaybackParameterBinding; import org.schabi.newpipe.util.SliderStrategy; import java.util.Objects; @@ -72,18 +71,7 @@ public class PlaybackParameterDialog extends DialogFragment { @State boolean skipSilence = DEFAULT_SKIP_SILENCE; - private SeekBar tempoSlider; - private TextView tempoCurrentText; - private TextView tempoStepDownText; - private TextView tempoStepUpText; - - private SeekBar pitchSlider; - private TextView pitchCurrentText; - private TextView pitchStepDownText; - private TextView pitchStepUpText; - - private CheckBox unhookingCheckbox; - private CheckBox skipSilenceCheckbox; + private DialogPlaybackParameterBinding binding; public static PlaybackParameterDialog newInstance( final double playbackTempo, @@ -110,7 +98,7 @@ public class PlaybackParameterDialog extends DialogFragment { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(final Context context) { + public void onAttach(@NonNull final Context context) { super.onAttach(context); if (context instanceof Callback) { callback = (Callback) context; @@ -120,7 +108,7 @@ public class PlaybackParameterDialog extends DialogFragment { } @Override - public void onSaveInstanceState(final Bundle outState) { + public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } @@ -135,12 +123,12 @@ public class PlaybackParameterDialog extends DialogFragment { assureCorrectAppLanguage(getContext()); Icepick.restoreInstanceState(this, savedInstanceState); - final View view = View.inflate(getContext(), R.layout.dialog_playback_parameter, null); - initUI(view); + binding = DialogPlaybackParameterBinding.inflate(LayoutInflater.from(getContext())); + initUI(); initUIData(); final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity()) - .setView(view) + .setView(binding.getRoot()) .setCancelable(true) .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { setAndUpdateTempo(initialTempo); @@ -163,37 +151,21 @@ public class PlaybackParameterDialog extends DialogFragment { // Control Views //////////////////////////////////////////////////////////////////////////*/ - private void initUI(@NonNull final View rootView) { + private void initUI() { // Tempo - tempoSlider = Objects.requireNonNull(rootView.findViewById(R.id.tempoSeekbar)); - tempoCurrentText = Objects.requireNonNull(rootView.findViewById(R.id.tempoCurrentText)); - tempoStepUpText = Objects.requireNonNull(rootView.findViewById(R.id.tempoStepUp)); - tempoStepDownText = Objects.requireNonNull(rootView.findViewById(R.id.tempoStepDown)); - - setText(rootView, R.id.tempoMinimumText, PlayerHelper::formatSpeed, MINIMUM_PLAYBACK_VALUE); - setText(rootView, R.id.tempoMaximumText, PlayerHelper::formatSpeed, MAXIMUM_PLAYBACK_VALUE); + setText(binding.tempoMinimumText, PlayerHelper::formatSpeed, MINIMUM_PLAYBACK_VALUE); + setText(binding.tempoMaximumText, PlayerHelper::formatSpeed, MAXIMUM_PLAYBACK_VALUE); // Pitch - pitchSlider = Objects.requireNonNull(rootView.findViewById(R.id.pitchSeekbar)); - pitchCurrentText = Objects.requireNonNull(rootView.findViewById(R.id.pitchCurrentText)); - pitchStepUpText = Objects.requireNonNull(rootView.findViewById(R.id.pitchStepUp)); - pitchStepDownText = Objects.requireNonNull(rootView.findViewById(R.id.pitchStepDown)); - - setText(rootView, R.id.pitchMinimumText, PlayerHelper::formatPitch, MINIMUM_PLAYBACK_VALUE); - setText(rootView, R.id.pitchMaximumText, PlayerHelper::formatPitch, MAXIMUM_PLAYBACK_VALUE); + setText(binding.pitchMinimumText, PlayerHelper::formatPitch, MINIMUM_PLAYBACK_VALUE); + setText(binding.pitchMaximumText, PlayerHelper::formatPitch, MAXIMUM_PLAYBACK_VALUE); // Steps - setupStepTextView(rootView, R.id.stepSizeOnePercent, STEP_1_PERCENT_VALUE); - setupStepTextView(rootView, R.id.stepSizeFivePercent, STEP_5_PERCENT_VALUE); - setupStepTextView(rootView, R.id.stepSizeTenPercent, STEP_10_PERCENT_VALUE); - setupStepTextView(rootView, R.id.stepSizeTwentyFivePercent, STEP_25_PERCENT_VALUE); - setupStepTextView(rootView, R.id.stepSizeOneHundredPercent, STEP_100_PERCENT_VALUE); - - // Bottom controls - unhookingCheckbox = - Objects.requireNonNull(rootView.findViewById(R.id.unhookCheckbox)); - skipSilenceCheckbox = - Objects.requireNonNull(rootView.findViewById(R.id.skipSilenceCheckbox)); + setupStepTextView(binding.stepSizeOnePercent, STEP_1_PERCENT_VALUE); + setupStepTextView(binding.stepSizeFivePercent, STEP_5_PERCENT_VALUE); + setupStepTextView(binding.stepSizeTenPercent, STEP_10_PERCENT_VALUE); + setupStepTextView(binding.stepSizeTwentyFivePercent, STEP_25_PERCENT_VALUE); + setupStepTextView(binding.stepSizeOneHundredPercent, STEP_100_PERCENT_VALUE); } private TextView setText( @@ -205,59 +177,47 @@ public class PlaybackParameterDialog extends DialogFragment { return textView; } - private TextView setText( - final View rootView, - @IdRes final int idRes, - final DoubleFunction formatter, - final double value - ) { - final TextView textView = rootView.findViewById(idRes); - setText(textView, formatter, value); - return textView; - } - private void setupStepTextView( - final View rootView, - @IdRes final int idRes, + final TextView textView, final double stepSizeValue ) { - setText(rootView, idRes, PlaybackParameterDialog::getPercentString, stepSizeValue) + setText(textView, PlaybackParameterDialog::getPercentString, stepSizeValue) .setOnClickListener(view -> setAndUpdateStepSize(stepSizeValue)); } private void initUIData() { // Tempo - tempoSlider.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); + binding.tempoSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); setAndUpdateTempo(tempo); - tempoSlider.setOnSeekBarChangeListener( + binding.tempoSeekbar.setOnSeekBarChangeListener( getTempoOrPitchSeekbarChangeListener(this::onTempoSliderUpdated)); registerOnStepClickListener( - tempoStepDownText, tempo, -1, this::onTempoSliderUpdated); + binding.tempoStepDown, tempo, -1, this::onTempoSliderUpdated); registerOnStepClickListener( - tempoStepUpText, tempo, 1, this::onTempoSliderUpdated); + binding.tempoStepUp, tempo, 1, this::onTempoSliderUpdated); // Pitch - pitchSlider.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); + binding.pitchSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); setAndUpdatePitch(pitch); - pitchSlider.setOnSeekBarChangeListener( + binding.pitchSeekbar.setOnSeekBarChangeListener( getTempoOrPitchSeekbarChangeListener(this::onPitchSliderUpdated)); registerOnStepClickListener( - pitchStepDownText, pitch, -1, this::onPitchSliderUpdated); + binding.pitchStepDown, pitch, -1, this::onPitchSliderUpdated); registerOnStepClickListener( - pitchStepUpText, pitch, 1, this::onPitchSliderUpdated); + binding.pitchStepUp, pitch, 1, this::onPitchSliderUpdated); // Steps setAndUpdateStepSize(stepSize); // Bottom controls // restore whether pitch and tempo are unhooked or not - unhookingCheckbox.setChecked(PreferenceManager + binding.unhookCheckbox.setChecked(PreferenceManager .getDefaultSharedPreferences(requireContext()) .getBoolean(getString(R.string.playback_unhook_key), true)); - unhookingCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + binding.unhookCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { // save whether pitch and tempo are unhooked or not PreferenceManager.getDefaultSharedPreferences(requireContext()) .edit() @@ -271,7 +231,7 @@ public class PlaybackParameterDialog extends DialogFragment { }); setAndUpdateSkipSilence(skipSilence); - skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + binding.skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { skipSilence = isChecked; updateCallback(); }); @@ -291,16 +251,16 @@ public class PlaybackParameterDialog extends DialogFragment { private void setAndUpdateStepSize(final double newStepSize) { this.stepSize = newStepSize; - tempoStepUpText.setText(getStepUpPercentString(newStepSize)); - tempoStepDownText.setText(getStepDownPercentString(newStepSize)); + binding.tempoStepUp.setText(getStepUpPercentString(newStepSize)); + binding.tempoStepDown.setText(getStepDownPercentString(newStepSize)); - pitchStepUpText.setText(getStepUpPercentString(newStepSize)); - pitchStepDownText.setText(getStepDownPercentString(newStepSize)); + binding.pitchStepUp.setText(getStepUpPercentString(newStepSize)); + binding.pitchStepDown.setText(getStepDownPercentString(newStepSize)); } private void setAndUpdateSkipSilence(final boolean newSkipSilence) { this.skipSilence = newSkipSilence; - skipSilenceCheckbox.setChecked(newSkipSilence); + binding.skipSilenceCheckbox.setChecked(newSkipSilence); } /*////////////////////////////////////////////////////////////////////////// @@ -333,7 +293,7 @@ public class PlaybackParameterDialog extends DialogFragment { } private void onTempoSliderUpdated(final double newTempo) { - if (!unhookingCheckbox.isChecked()) { + if (!binding.unhookCheckbox.isChecked()) { setSliders(newTempo); } else { setAndUpdateTempo(newTempo); @@ -341,7 +301,7 @@ public class PlaybackParameterDialog extends DialogFragment { } private void onPitchSliderUpdated(final double newPitch) { - if (!unhookingCheckbox.isChecked()) { + if (!binding.unhookCheckbox.isChecked()) { setSliders(newPitch); } else { setAndUpdatePitch(newPitch); @@ -355,14 +315,14 @@ public class PlaybackParameterDialog extends DialogFragment { private void setAndUpdateTempo(final double newTempo) { this.tempo = newTempo; - tempoSlider.setProgress(QUADRATIC_STRATEGY.progressOf(tempo)); - setText(tempoCurrentText, PlayerHelper::formatSpeed, tempo); + binding.tempoSeekbar.setProgress(QUADRATIC_STRATEGY.progressOf(tempo)); + setText(binding.tempoCurrentText, PlayerHelper::formatSpeed, tempo); } private void setAndUpdatePitch(final double newPitch) { this.pitch = newPitch; - pitchSlider.setProgress(QUADRATIC_STRATEGY.progressOf(pitch)); - setText(pitchCurrentText, PlayerHelper::formatPitch, pitch); + binding.pitchSeekbar.setProgress(QUADRATIC_STRATEGY.progressOf(pitch)); + setText(binding.pitchCurrentText, PlayerHelper::formatPitch, pitch); } /*////////////////////////////////////////////////////////////////////////// From 6e0c3804097a1e3749d329c82e8cca3c72d7ec18 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Mon, 28 Feb 2022 21:02:43 +0100 Subject: [PATCH 005/106] Remove redundant attributes --- .../res/layout/dialog_playback_parameter.xml | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 862b2ea67..27cf0dbd6 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -39,7 +39,6 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentStart="true" - android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:background="?attr/selectableItemBackground" android:clickable="true" @@ -57,9 +56,7 @@ android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:layout_toStartOf="@id/tempoStepUp" - android:layout_toLeftOf="@id/tempoStepUp" android:layout_toEndOf="@id/tempoStepDown" - android:layout_toRightOf="@id/tempoStepDown" android:orientation="horizontal"> Date: Mon, 28 Feb 2022 21:04:24 +0100 Subject: [PATCH 006/106] Remove invalid parameters --- app/src/main/res/layout/dialog_playback_parameter.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 27cf0dbd6..87c26b831 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -463,8 +463,6 @@ android:id="@+id/adjustBySemitonesCheckbox" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_below="@id/skipSilenceCheckbox" - android:layout_centerHorizontal="true" android:checked="false" android:clickable="true" android:focusable="true" From a4c083e7f98c535993c9e22d9d3ae99d5c410a0c Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Tue, 1 Mar 2022 20:52:48 +0100 Subject: [PATCH 007/106] Rework dialog * De-Duplicated some fields * Use a container for the pitch controls * Name pitch related elements correctly --- .../res/layout/dialog_playback_parameter.xml | 310 +++++++++--------- 1 file changed, 157 insertions(+), 153 deletions(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 87c26b831..47394b724 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -29,7 +29,7 @@ @@ -146,203 +146,207 @@ android:textStyle="bold" /> - - + android:layout_marginTop="3dp"> - - + tools:text="-5%" /> + + + + + + + + + + + - - + tools:text="+5%" /> - - - - - - - - - - - - - + android:layout_height="match_parent" + android:layout_marginLeft="4dp" + android:layout_marginRight="4dp" + android:layout_toStartOf="@+id/pitchSemitoneStepUp" + android:layout_toEndOf="@+id/pitchSemitoneStepDown" + android:orientation="horizontal"> - + + + + + + + + + + + Date: Tue, 1 Mar 2022 21:19:30 +0100 Subject: [PATCH 008/106] Shrunk dialog a bit --- app/src/main/res/layout/dialog_playback_parameter.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 47394b724..1ab9a95e9 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -356,7 +356,7 @@ From dae5aa38a83a892f43a3589a21bada854601273d Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Wed, 2 Mar 2022 20:58:14 +0100 Subject: [PATCH 009/106] Fine tuned dialog (no scrollers in fullscreen on 5in phone) --- .../res/layout/dialog_playback_parameter.xml | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 1ab9a95e9..75269ffd3 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -31,7 +31,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tempoControlText" - android:layout_marginTop="3dp" + android:layout_marginTop="1dp" android:orientation="horizontal"> @@ -129,9 +129,9 @@ android:layout_height="1dp" android:layout_below="@id/tempoControl" android:layout_marginStart="12dp" - android:layout_marginTop="6dp" - android:layout_marginEnd="6dp" - android:layout_marginBottom="6dp" + android:layout_marginTop="4dp" + android:layout_marginEnd="12dp" + android:layout_marginBottom="4dp" android:background="?attr/separator_color" /> + android:layout_marginTop="1dp"> @@ -319,7 +319,7 @@ android:layout_height="wrap_content" android:layout_below="@+id/pitchSemitoneCurrentText" android:max="24" - android:paddingBottom="4dp" + android:paddingBottom="2dp" android:progress="12" /> @@ -348,9 +348,9 @@ android:layout_height="1dp" android:layout_below="@+id/pitchControlContainer" android:layout_marginStart="12dp" - android:layout_marginTop="6dp" + android:layout_marginTop="4dp" android:layout_marginEnd="12dp" - android:layout_marginBottom="6dp" + android:layout_marginBottom="4dp" android:background="?attr/separator_color" /> Date: Wed, 2 Mar 2022 21:00:19 +0100 Subject: [PATCH 010/106] Reworked/Implemented PlaybackParameterDialog functionallity * Add support for semitones * Fixed some minor bugs * Improved some methods --- .../helper/PlaybackParameterDialog.java | 320 +++++++++++++----- .../player/helper/PlayerSemitoneHelper.java | 37 ++ 2 files changed, 264 insertions(+), 93 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index e1874fec0..709216ece 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -8,11 +8,14 @@ import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; import android.widget.SeekBar; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceManager; @@ -22,8 +25,10 @@ import org.schabi.newpipe.databinding.DialogPlaybackParameterBinding; import org.schabi.newpipe.util.SliderStrategy; import java.util.Objects; +import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.DoubleFunction; +import java.util.function.DoubleSupplier; import icepick.Icepick; import icepick.State; @@ -32,8 +37,8 @@ public class PlaybackParameterDialog extends DialogFragment { private static final String TAG = "PlaybackParameterDialog"; // Minimum allowable range in ExoPlayer - private static final double MINIMUM_PLAYBACK_VALUE = 0.10f; - private static final double MAXIMUM_PLAYBACK_VALUE = 3.00f; + private static final double MIN_PLAYBACK_VALUE = 0.10f; + private static final double MAX_PLAYBACK_VALUE = 3.00f; private static final double STEP_1_PERCENT_VALUE = 0.01f; private static final double STEP_5_PERCENT_VALUE = 0.05f; @@ -42,30 +47,42 @@ public class PlaybackParameterDialog extends DialogFragment { private static final double STEP_100_PERCENT_VALUE = 1.00f; private static final double DEFAULT_TEMPO = 1.00f; - private static final double DEFAULT_PITCH = 1.00f; + private static final double DEFAULT_PITCH_PERCENT = 1.00f; private static final double DEFAULT_STEP = STEP_25_PERCENT_VALUE; private static final boolean DEFAULT_SKIP_SILENCE = false; private static final SliderStrategy QUADRATIC_STRATEGY = new SliderStrategy.Quadratic( - MINIMUM_PLAYBACK_VALUE, - MAXIMUM_PLAYBACK_VALUE, + MIN_PLAYBACK_VALUE, + MAX_PLAYBACK_VALUE, 1.00f, 10_000); + private static final SliderStrategy SEMITONE_STRATEGY = new SliderStrategy() { + @Override + public int progressOf(final double value) { + return PlayerSemitoneHelper.percentToSemitones(value) + 12; + } + + @Override + public double valueOf(final int progress) { + return PlayerSemitoneHelper.semitonesToPercent(progress - 12); + } + }; + @Nullable private Callback callback; @State double initialTempo = DEFAULT_TEMPO; @State - double initialPitch = DEFAULT_PITCH; + double initialPitchPercent = DEFAULT_PITCH_PERCENT; @State boolean initialSkipSilence = DEFAULT_SKIP_SILENCE; @State double tempo = DEFAULT_TEMPO; @State - double pitch = DEFAULT_PITCH; + double pitchPercent = DEFAULT_PITCH_PERCENT; @State double stepSize = DEFAULT_STEP; @State @@ -83,11 +100,11 @@ public class PlaybackParameterDialog extends DialogFragment { dialog.callback = callback; dialog.initialTempo = playbackTempo; - dialog.initialPitch = playbackPitch; + dialog.initialPitchPercent = playbackPitch; dialog.initialSkipSilence = playbackSkipSilence; dialog.tempo = dialog.initialTempo; - dialog.pitch = dialog.initialPitch; + dialog.pitchPercent = dialog.initialPitchPercent; dialog.skipSilence = dialog.initialSkipSilence; return dialog; @@ -125,20 +142,19 @@ public class PlaybackParameterDialog extends DialogFragment { binding = DialogPlaybackParameterBinding.inflate(LayoutInflater.from(getContext())); initUI(); - initUIData(); final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireActivity()) .setView(binding.getRoot()) .setCancelable(true) .setNegativeButton(R.string.cancel, (dialogInterface, i) -> { setAndUpdateTempo(initialTempo); - setAndUpdatePitch(initialPitch); + setAndUpdatePitch(initialPitchPercent); setAndUpdateSkipSilence(initialSkipSilence); updateCallback(); }) .setNeutralButton(R.string.playback_reset, (dialogInterface, i) -> { setAndUpdateTempo(DEFAULT_TEMPO); - setAndUpdatePitch(DEFAULT_PITCH); + setAndUpdatePitch(DEFAULT_PITCH_PERCENT); setAndUpdateSkipSilence(DEFAULT_SKIP_SILENCE); updateCallback(); }) @@ -153,12 +169,63 @@ public class PlaybackParameterDialog extends DialogFragment { private void initUI() { // Tempo - setText(binding.tempoMinimumText, PlayerHelper::formatSpeed, MINIMUM_PLAYBACK_VALUE); - setText(binding.tempoMaximumText, PlayerHelper::formatSpeed, MAXIMUM_PLAYBACK_VALUE); + setText(binding.tempoMinimumText, PlayerHelper::formatSpeed, MIN_PLAYBACK_VALUE); + setText(binding.tempoMaximumText, PlayerHelper::formatSpeed, MAX_PLAYBACK_VALUE); - // Pitch - setText(binding.pitchMinimumText, PlayerHelper::formatPitch, MINIMUM_PLAYBACK_VALUE); - setText(binding.pitchMaximumText, PlayerHelper::formatPitch, MAXIMUM_PLAYBACK_VALUE); + binding.tempoSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PLAYBACK_VALUE)); + setAndUpdateTempo(tempo); + binding.tempoSeekbar.setOnSeekBarChangeListener( + getTempoOrPitchSeekbarChangeListener( + QUADRATIC_STRATEGY, + this::onTempoSliderUpdated)); + + registerOnStepClickListener( + binding.tempoStepDown, + () -> tempo, + -1, + this::onTempoSliderUpdated); + registerOnStepClickListener( + binding.tempoStepUp, + () -> tempo, + 1, + this::onTempoSliderUpdated); + + // Pitch - Percent + setText(binding.pitchPercentMinimumText, PlayerHelper::formatPitch, MIN_PLAYBACK_VALUE); + setText(binding.pitchPercentMaximumText, PlayerHelper::formatPitch, MAX_PLAYBACK_VALUE); + + binding.pitchPercentSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PLAYBACK_VALUE)); + setAndUpdatePitch(pitchPercent); + binding.pitchPercentSeekbar.setOnSeekBarChangeListener( + getTempoOrPitchSeekbarChangeListener( + QUADRATIC_STRATEGY, + this::onPitchPercentSliderUpdated)); + + registerOnStepClickListener( + binding.pitchPercentStepDown, + () -> pitchPercent, + -1, + this::onPitchPercentSliderUpdated); + registerOnStepClickListener( + binding.pitchPercentStepUp, + () -> pitchPercent, + 1, + this::onPitchPercentSliderUpdated); + + // Pitch - Semitone + binding.pitchSemitoneSeekbar.setOnSeekBarChangeListener( + getTempoOrPitchSeekbarChangeListener( + SEMITONE_STRATEGY, + this::onPitchPercentSliderUpdated)); + + registerOnSemitoneStepClickListener( + binding.pitchSemitoneStepDown, + -1, + this::onPitchPercentSliderUpdated); + registerOnSemitoneStepClickListener( + binding.pitchSemitoneStepUp, + 1, + this::onPitchPercentSliderUpdated); // Steps setupStepTextView(binding.stepSizeOnePercent, STEP_1_PERCENT_VALUE); @@ -166,6 +233,34 @@ public class PlaybackParameterDialog extends DialogFragment { setupStepTextView(binding.stepSizeTenPercent, STEP_10_PERCENT_VALUE); setupStepTextView(binding.stepSizeTwentyFivePercent, STEP_25_PERCENT_VALUE); setupStepTextView(binding.stepSizeOneHundredPercent, STEP_100_PERCENT_VALUE); + + setAndUpdateStepSize(stepSize); + + // Bottom controls + bindCheckboxWithBoolPref( + binding.unhookCheckbox, + R.string.playback_unhook_key, + true, + isChecked -> { + if (!isChecked) { + // when unchecked, slide back to the minimum of current tempo or pitch + setSliders(Math.min(pitchPercent, tempo)); + updateCallback(); + } + }); + + setAndUpdateSkipSilence(skipSilence); + binding.skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + skipSilence = isChecked; + updateCallback(); + }); + + bindCheckboxWithBoolPref( + binding.adjustBySemitonesCheckbox, + R.string.playback_adjust_by_semitones_key, + false, + this::showPitchSemitonesOrPercent + ); } private TextView setText( @@ -177,6 +272,31 @@ public class PlaybackParameterDialog extends DialogFragment { return textView; } + private void registerOnStepClickListener( + final TextView stepTextView, + final DoubleSupplier currentValueSupplier, + final double direction, // -1 for step down, +1 for step up + final DoubleConsumer newValueConsumer + ) { + stepTextView.setOnClickListener(view -> { + newValueConsumer.accept( + currentValueSupplier.getAsDouble() + 1 * stepSize * direction); + updateCallback(); + }); + } + + private void registerOnSemitoneStepClickListener( + final TextView stepTextView, + final int direction, // -1 for step down, +1 for step up + final DoubleConsumer newValueConsumer + ) { + stepTextView.setOnClickListener(view -> { + newValueConsumer.accept(PlayerSemitoneHelper.semitonesToPercent( + PlayerSemitoneHelper.percentToSemitones(this.pitchPercent) + direction)); + updateCallback(); + }); + } + private void setupStepTextView( final TextView textView, final double stepSizeValue @@ -185,77 +305,14 @@ public class PlaybackParameterDialog extends DialogFragment { .setOnClickListener(view -> setAndUpdateStepSize(stepSizeValue)); } - private void initUIData() { - // Tempo - binding.tempoSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); - setAndUpdateTempo(tempo); - binding.tempoSeekbar.setOnSeekBarChangeListener( - getTempoOrPitchSeekbarChangeListener(this::onTempoSliderUpdated)); - - registerOnStepClickListener( - binding.tempoStepDown, tempo, -1, this::onTempoSliderUpdated); - registerOnStepClickListener( - binding.tempoStepUp, tempo, 1, this::onTempoSliderUpdated); - - // Pitch - binding.pitchSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAXIMUM_PLAYBACK_VALUE)); - setAndUpdatePitch(pitch); - binding.pitchSeekbar.setOnSeekBarChangeListener( - getTempoOrPitchSeekbarChangeListener(this::onPitchSliderUpdated)); - - registerOnStepClickListener( - binding.pitchStepDown, pitch, -1, this::onPitchSliderUpdated); - registerOnStepClickListener( - binding.pitchStepUp, pitch, 1, this::onPitchSliderUpdated); - - // Steps - setAndUpdateStepSize(stepSize); - - // Bottom controls - // restore whether pitch and tempo are unhooked or not - binding.unhookCheckbox.setChecked(PreferenceManager - .getDefaultSharedPreferences(requireContext()) - .getBoolean(getString(R.string.playback_unhook_key), true)); - - binding.unhookCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { - // save whether pitch and tempo are unhooked or not - PreferenceManager.getDefaultSharedPreferences(requireContext()) - .edit() - .putBoolean(getString(R.string.playback_unhook_key), isChecked) - .apply(); - - if (!isChecked) { - // when unchecked, slide back to the minimum of current tempo or pitch - setSliders(Math.min(pitch, tempo)); - } - }); - - setAndUpdateSkipSilence(skipSilence); - binding.skipSilenceCheckbox.setOnCheckedChangeListener((compoundButton, isChecked) -> { - skipSilence = isChecked; - updateCallback(); - }); - } - - private void registerOnStepClickListener( - final TextView stepTextView, - final double currentValue, - final double direction, // -1 for step down, +1 for step up - final DoubleConsumer newValueConsumer - ) { - stepTextView.setOnClickListener(view -> - newValueConsumer.accept(currentValue * direction) - ); - } - private void setAndUpdateStepSize(final double newStepSize) { this.stepSize = newStepSize; binding.tempoStepUp.setText(getStepUpPercentString(newStepSize)); binding.tempoStepDown.setText(getStepDownPercentString(newStepSize)); - binding.pitchStepUp.setText(getStepUpPercentString(newStepSize)); - binding.pitchStepDown.setText(getStepDownPercentString(newStepSize)); + binding.pitchPercentStepUp.setText(getStepUpPercentString(newStepSize)); + binding.pitchPercentStepDown.setText(getStepDownPercentString(newStepSize)); } private void setAndUpdateSkipSilence(final boolean newSkipSilence) { @@ -263,19 +320,72 @@ public class PlaybackParameterDialog extends DialogFragment { binding.skipSilenceCheckbox.setChecked(newSkipSilence); } + private void bindCheckboxWithBoolPref( + @NonNull final CheckBox checkBox, + @StringRes final int resId, + final boolean defaultValue, + @Nullable final Consumer onInitialValueOrValueChange + ) { + final boolean prefValue = PreferenceManager + .getDefaultSharedPreferences(requireContext()) + .getBoolean(getString(resId), defaultValue); + + checkBox.setChecked(prefValue); + + if (onInitialValueOrValueChange != null) { + onInitialValueOrValueChange.accept(prefValue); + } + + checkBox.setOnCheckedChangeListener((compoundButton, isChecked) -> { + // save whether pitch and tempo are unhooked or not + PreferenceManager.getDefaultSharedPreferences(requireContext()) + .edit() + .putBoolean(getString(resId), isChecked) + .apply(); + + if (onInitialValueOrValueChange != null) { + onInitialValueOrValueChange.accept(isChecked); + } + }); + } + + private void showPitchSemitonesOrPercent(final boolean semitones) { + binding.pitchPercentControl.setVisibility(semitones ? View.GONE : View.VISIBLE); + binding.pitchSemitoneControl.setVisibility(semitones ? View.VISIBLE : View.GONE); + + if (semitones) { + // Recalculate pitch percent when changing to semitone + // (as it could be an invalid semitone value) + final double newPitchPercent = calcValidPitch(pitchPercent); + + // If the values differ set the new pitch + if (this.pitchPercent != newPitchPercent) { + if (DEBUG) { + Log.d(TAG, "Bringing pitchPercent to correct corresponding semitone: " + + "currentPitchPercent = " + pitchPercent + ", " + + "newPitchPercent = " + newPitchPercent + ); + } + this.onPitchPercentSliderUpdated(newPitchPercent); + updateCallback(); + } + } + } + /*////////////////////////////////////////////////////////////////////////// // Sliders //////////////////////////////////////////////////////////////////////////*/ private SeekBar.OnSeekBarChangeListener getTempoOrPitchSeekbarChangeListener( + final SliderStrategy sliderStrategy, final DoubleConsumer newValueConsumer ) { return new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) { - if (fromUser) { // this change is first in chain - newValueConsumer.accept(QUADRATIC_STRATEGY.valueOf(progress)); + if (fromUser) { // ensure that the user triggered the change + newValueConsumer.accept(sliderStrategy.valueOf(progress)); updateCallback(); } } @@ -300,7 +410,7 @@ public class PlaybackParameterDialog extends DialogFragment { } } - private void onPitchSliderUpdated(final double newPitch) { + private void onPitchPercentSliderUpdated(final double newPitch) { if (!binding.unhookCheckbox.isChecked()) { setSliders(newPitch); } else { @@ -314,15 +424,39 @@ public class PlaybackParameterDialog extends DialogFragment { } private void setAndUpdateTempo(final double newTempo) { - this.tempo = newTempo; + this.tempo = calcValidTempo(newTempo); + binding.tempoSeekbar.setProgress(QUADRATIC_STRATEGY.progressOf(tempo)); setText(binding.tempoCurrentText, PlayerHelper::formatSpeed, tempo); } private void setAndUpdatePitch(final double newPitch) { - this.pitch = newPitch; - binding.pitchSeekbar.setProgress(QUADRATIC_STRATEGY.progressOf(pitch)); - setText(binding.pitchCurrentText, PlayerHelper::formatPitch, pitch); + this.pitchPercent = calcValidPitch(newPitch); + + binding.pitchPercentSeekbar.setProgress(QUADRATIC_STRATEGY.progressOf(pitchPercent)); + binding.pitchSemitoneSeekbar.setProgress(SEMITONE_STRATEGY.progressOf(pitchPercent)); + setText(binding.pitchPercentCurrentText, + PlayerHelper::formatPitch, + pitchPercent); + setText(binding.pitchSemitoneCurrentText, + PlayerSemitoneHelper::formatPitchSemitones, + pitchPercent); + } + + private double calcValidTempo(final double newTempo) { + return Math.max(MIN_PLAYBACK_VALUE, Math.min(MAX_PLAYBACK_VALUE, newTempo)); + } + + private double calcValidPitch(final double newPitch) { + final double calcPitch = + Math.max(MIN_PLAYBACK_VALUE, Math.min(MAX_PLAYBACK_VALUE, newPitch)); + + if (!binding.adjustBySemitonesCheckbox.isChecked()) { + return calcPitch; + } + + return PlayerSemitoneHelper.semitonesToPercent( + PlayerSemitoneHelper.percentToSemitones(calcPitch)); } /*////////////////////////////////////////////////////////////////////////// @@ -335,12 +469,12 @@ public class PlaybackParameterDialog extends DialogFragment { } if (DEBUG) { Log.d(TAG, "Updating callback: " - + "tempo = [" + tempo + "], " - + "pitch = [" + pitch + "], " - + "skipSilence = [" + skipSilence + "]" + + "tempo = " + tempo + ", " + + "pitchPercent = " + pitchPercent + ", " + + "skipSilence = " + skipSilence ); } - callback.onPlaybackParameterChanged((float) tempo, (float) pitch, skipSilence); + callback.onPlaybackParameterChanged((float) tempo, (float) pitchPercent, skipSilence); } @NonNull diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java new file mode 100644 index 000000000..abbcc2c82 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java @@ -0,0 +1,37 @@ +package org.schabi.newpipe.player.helper; + +/** + * Converts between percent and 12-tone equal temperament semitones. + *
+ * @see + * + * Wikipedia: Equal temperament#Twelve-tone equal temperament + * + */ +public final class PlayerSemitoneHelper { + public static final int TONES = 12; + + private PlayerSemitoneHelper() { + // No impl + } + + public static String formatPitchSemitones(final double percent) { + return formatPitchSemitones(percentToSemitones(percent)); + } + + public static String formatPitchSemitones(final int semitones) { + return semitones > 0 ? "+" + semitones : "" + semitones; + } + + public static double semitonesToPercent(final int semitones) { + return Math.pow(2, ensureSemitonesInRange(semitones) / (double) TONES); + } + + public static int percentToSemitones(final double percent) { + return ensureSemitonesInRange((int) Math.round(TONES * Math.log(percent) / Math.log(2))); + } + + private static int ensureSemitonesInRange(final int semitones) { + return Math.max(-TONES, Math.min(TONES, semitones)); + } +} From 321cf8bf7d7a419913f58697cb4cb7e5630212d7 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 4 Mar 2022 21:33:21 +0100 Subject: [PATCH 011/106] Fine tuned dialog --- .../res/layout/dialog_playback_parameter.xml | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 75269ffd3..640475f39 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -1,5 +1,6 @@ + android:orientation="horizontal" + tools:visibility="gone"> + tools:text="0" + tools:ignore="RelativeOverlap" /> + android:textColor="?attr/colorAccent" + tools:text="1%" /> + android:textColor="?attr/colorAccent" + tools:text="5%" /> + android:textColor="?attr/colorAccent" + tools:text="10%" /> + android:textColor="?attr/colorAccent" + tools:text="25%" /> - + android:textColor="?attr/colorAccent" + tools:text="100%" /> Date: Fri, 4 Mar 2022 21:34:45 +0100 Subject: [PATCH 012/106] Code improvements regarding stepSize --- .../helper/PlaybackParameterDialog.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 709216ece..eab64e483 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -84,8 +84,6 @@ public class PlaybackParameterDialog extends DialogFragment { @State double pitchPercent = DEFAULT_PITCH_PERCENT; @State - double stepSize = DEFAULT_STEP; - @State boolean skipSilence = DEFAULT_SKIP_SILENCE; private DialogPlaybackParameterBinding binding; @@ -228,13 +226,10 @@ public class PlaybackParameterDialog extends DialogFragment { this::onPitchPercentSliderUpdated); // Steps - setupStepTextView(binding.stepSizeOnePercent, STEP_1_PERCENT_VALUE); - setupStepTextView(binding.stepSizeFivePercent, STEP_5_PERCENT_VALUE); - setupStepTextView(binding.stepSizeTenPercent, STEP_10_PERCENT_VALUE); - setupStepTextView(binding.stepSizeTwentyFivePercent, STEP_25_PERCENT_VALUE); - setupStepTextView(binding.stepSizeOneHundredPercent, STEP_100_PERCENT_VALUE); - - setAndUpdateStepSize(stepSize); + getStepSizeComponentMappings() + .forEach(this::setupStepTextView); + // Initialize UI + setStepSizeToUI(getCurrentStepSize()); // Bottom controls bindCheckboxWithBoolPref( @@ -263,13 +258,12 @@ public class PlaybackParameterDialog extends DialogFragment { ); } - private TextView setText( + private void setText( final TextView textView, final DoubleFunction formatter, final double value ) { Objects.requireNonNull(textView).setText(formatter.apply(value)); - return textView; } private void registerOnStepClickListener( @@ -280,7 +274,7 @@ public class PlaybackParameterDialog extends DialogFragment { ) { stepTextView.setOnClickListener(view -> { newValueConsumer.accept( - currentValueSupplier.getAsDouble() + 1 * stepSize * direction); + currentValueSupplier.getAsDouble() + 1 * getCurrentStepSize() * direction); updateCallback(); }); } @@ -315,16 +309,22 @@ public class PlaybackParameterDialog extends DialogFragment { binding.pitchPercentStepDown.setText(getStepDownPercentString(newStepSize)); } + private double getCurrentStepSize() { + return PreferenceManager.getDefaultSharedPreferences(requireContext()) + .getFloat(getString(R.string.adjustment_step_key), (float) DEFAULT_STEP); + } + private void setAndUpdateSkipSilence(final boolean newSkipSilence) { this.skipSilence = newSkipSilence; binding.skipSilenceCheckbox.setChecked(newSkipSilence); } + @SuppressWarnings("SameParameterValue") // this method was written to be reusable private void bindCheckboxWithBoolPref( @NonNull final CheckBox checkBox, @StringRes final int resId, final boolean defaultValue, - @Nullable final Consumer onInitialValueOrValueChange + @NonNull final Consumer onInitialValueOrValueChange ) { final boolean prefValue = PreferenceManager .getDefaultSharedPreferences(requireContext()) @@ -332,9 +332,7 @@ public class PlaybackParameterDialog extends DialogFragment { checkBox.setChecked(prefValue); - if (onInitialValueOrValueChange != null) { - onInitialValueOrValueChange.accept(prefValue); - } + onInitialValueOrValueChange.accept(prefValue); checkBox.setOnCheckedChangeListener((compoundButton, isChecked) -> { // save whether pitch and tempo are unhooked or not @@ -343,9 +341,7 @@ public class PlaybackParameterDialog extends DialogFragment { .putBoolean(getString(resId), isChecked) .apply(); - if (onInitialValueOrValueChange != null) { - onInitialValueOrValueChange.accept(isChecked); - } + onInitialValueOrValueChange.accept(isChecked); }); } From 4b0653658273f456ddbc56a86b1695073d982895 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 4 Mar 2022 21:37:11 +0100 Subject: [PATCH 013/106] Reworked switching to semitones Using an expandable Tab-like component instead of a combobox --- .../schabi/newpipe/local/feed/FeedFragment.kt | 16 +- .../helper/PlaybackParameterDialog.java | 169 ++++++++++++++---- .../schabi/newpipe/util/DrawableResolver.kt | 26 +++ .../res/layout/dialog_playback_parameter.xml | 59 ++++-- app/src/main/res/values/strings.xml | 2 + 5 files changed, 209 insertions(+), 63 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index e97629f31..e8e78feda 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -25,7 +25,6 @@ import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.graphics.Typeface -import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.os.Bundle import android.os.Parcelable @@ -37,7 +36,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Button -import androidx.annotation.AttrRes import androidx.annotation.Nullable import androidx.appcompat.app.AlertDialog import androidx.appcompat.content.res.AppCompatResources @@ -77,6 +75,7 @@ import org.schabi.newpipe.local.feed.item.StreamItem import org.schabi.newpipe.local.feed.service.FeedLoadService import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.util.DeviceUtils +import org.schabi.newpipe.util.DrawableResolver.Companion.resolveDrawable import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountStreams @@ -579,19 +578,6 @@ class FeedFragment : BaseStateFragment() { lastNewItemsCount = highlightCount } - private fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { - return androidx.core.content.ContextCompat.getDrawable( - context, - android.util.TypedValue().apply { - context.theme.resolveAttribute( - attrResId, - this, - true - ) - }.resourceId - ) - } - private fun showNewItemsLoaded() { tryGetNewItemsLoadedButton()?.clearAnimation() tryGetNewItemsLoadedButton() diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index eab64e483..902222cc5 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -1,10 +1,14 @@ package org.schabi.newpipe.player.helper; +import static org.schabi.newpipe.ktx.ViewUtils.animateRotation; import static org.schabi.newpipe.player.Player.DEBUG; +import static org.schabi.newpipe.util.DrawableResolver.resolveDrawable; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import android.app.Dialog; import android.content.Context; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -22,8 +26,11 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.DialogPlaybackParameterBinding; +import org.schabi.newpipe.player.Player; import org.schabi.newpipe.util.SliderStrategy; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import java.util.function.DoubleConsumer; @@ -40,6 +47,9 @@ public class PlaybackParameterDialog extends DialogFragment { private static final double MIN_PLAYBACK_VALUE = 0.10f; private static final double MAX_PLAYBACK_VALUE = 3.00f; + private static final boolean PITCH_CTRL_MODE_PERCENT = false; + private static final boolean PITCH_CTRL_MODE_SEMITONE = true; + private static final double STEP_1_PERCENT_VALUE = 0.01f; private static final double STEP_5_PERCENT_VALUE = 0.05f; private static final double STEP_10_PERCENT_VALUE = 0.10f; @@ -188,6 +198,22 @@ public class PlaybackParameterDialog extends DialogFragment { 1, this::onTempoSliderUpdated); + // Pitch + binding.pitchToogleControlModes.setOnClickListener(v -> { + final boolean isCurrentlyVisible = + binding.pitchControlModeTabs.getVisibility() == View.GONE; + binding.pitchControlModeTabs.setVisibility(isCurrentlyVisible + ? View.VISIBLE + : View.GONE); + animateRotation(binding.pitchToogleControlModes, + Player.DEFAULT_CONTROLS_DURATION, + isCurrentlyVisible ? 180 : 0); + }); + + getPitchControlModeComponentMappings() + .forEach(this::setupPitchControlModeTextView); + changePitchControlMode(isCurrentPitchControlModeSemitone()); + // Pitch - Percent setText(binding.pitchPercentMinimumText, PlayerHelper::formatPitch, MIN_PLAYBACK_VALUE); setText(binding.pitchPercentMaximumText, PlayerHelper::formatPitch, MAX_PLAYBACK_VALUE); @@ -249,13 +275,6 @@ public class PlaybackParameterDialog extends DialogFragment { skipSilence = isChecked; updateCallback(); }); - - bindCheckboxWithBoolPref( - binding.adjustBySemitonesCheckbox, - R.string.playback_adjust_by_semitones_key, - false, - this::showPitchSemitonesOrPercent - ); } private void setText( @@ -291,17 +310,114 @@ public class PlaybackParameterDialog extends DialogFragment { }); } - private void setupStepTextView( - final TextView textView, - final double stepSizeValue + private void setupPitchControlModeTextView( + final boolean semitones, + final TextView textView ) { - setText(textView, PlaybackParameterDialog::getPercentString, stepSizeValue) - .setOnClickListener(view -> setAndUpdateStepSize(stepSizeValue)); + textView.setOnClickListener(view -> { + PreferenceManager.getDefaultSharedPreferences(requireContext()) + .edit() + .putBoolean(getString(R.string.playback_adjust_by_semitones_key), semitones) + .apply(); + + changePitchControlMode(semitones); + }); } - private void setAndUpdateStepSize(final double newStepSize) { - this.stepSize = newStepSize; + private Map getPitchControlModeComponentMappings() { + final Map mappings = new HashMap<>(); + mappings.put(PITCH_CTRL_MODE_PERCENT, binding.pitchControlModePercent); + mappings.put(PITCH_CTRL_MODE_SEMITONE, binding.pitchControlModeSemitone); + return mappings; + } + private void changePitchControlMode(final boolean semitones) { + // Bring all textviews into a normal state + final Map pitchCtrlModeComponentMapping = + getPitchControlModeComponentMappings(); + pitchCtrlModeComponentMapping.forEach((v, textView) -> textView.setBackground( + resolveDrawable(requireContext(), R.attr.selectableItemBackground))); + + // Mark the selected textview + final TextView textView = pitchCtrlModeComponentMapping.get(semitones); + if (textView != null) { + textView.setBackground(new LayerDrawable(new Drawable[]{ + resolveDrawable(requireContext(), R.attr.dashed_border), + resolveDrawable(requireContext(), R.attr.selectableItemBackground) + })); + } + + // Show or hide component + binding.pitchPercentControl.setVisibility(semitones ? View.GONE : View.VISIBLE); + binding.pitchSemitoneControl.setVisibility(semitones ? View.VISIBLE : View.GONE); + + if (semitones) { + // Recalculate pitch percent when changing to semitone + // (as it could be an invalid semitone value) + final double newPitchPercent = calcValidPitch(pitchPercent); + + // If the values differ set the new pitch + if (this.pitchPercent != newPitchPercent) { + if (DEBUG) { + Log.d(TAG, "Bringing pitchPercent to correct corresponding semitone: " + + "currentPitchPercent = " + pitchPercent + ", " + + "newPitchPercent = " + newPitchPercent + ); + } + this.onPitchPercentSliderUpdated(newPitchPercent); + updateCallback(); + } + } + } + + private boolean isCurrentPitchControlModeSemitone() { + return PreferenceManager.getDefaultSharedPreferences(requireContext()) + .getBoolean( + getString(R.string.playback_adjust_by_semitones_key), + PITCH_CTRL_MODE_PERCENT); + } + + private void setupStepTextView( + final double stepSizeValue, + final TextView textView + ) { + setText(textView, PlaybackParameterDialog::getPercentString, stepSizeValue); + textView.setOnClickListener(view -> { + PreferenceManager.getDefaultSharedPreferences(requireContext()) + .edit() + .putFloat(getString(R.string.adjustment_step_key), (float) stepSizeValue) + .apply(); + + setStepSizeToUI(stepSizeValue); + }); + } + + private Map getStepSizeComponentMappings() { + final Map mappings = new HashMap<>(); + mappings.put(STEP_1_PERCENT_VALUE, binding.stepSizeOnePercent); + mappings.put(STEP_5_PERCENT_VALUE, binding.stepSizeFivePercent); + mappings.put(STEP_10_PERCENT_VALUE, binding.stepSizeTenPercent); + mappings.put(STEP_25_PERCENT_VALUE, binding.stepSizeTwentyFivePercent); + mappings.put(STEP_100_PERCENT_VALUE, binding.stepSizeOneHundredPercent); + return mappings; + } + + private void setStepSizeToUI(final double newStepSize) { + // Bring all textviews into a normal state + final Map stepSiteComponentMapping = getStepSizeComponentMappings(); + stepSiteComponentMapping.forEach((v, textView) -> textView.setBackground( + resolveDrawable(requireContext(), R.attr.selectableItemBackground))); + + // Mark the selected textview + final TextView textView = stepSiteComponentMapping.get(newStepSize); + if (textView != null) { + textView.setBackground(new LayerDrawable(new Drawable[]{ + resolveDrawable(requireContext(), R.attr.dashed_border), + resolveDrawable(requireContext(), R.attr.selectableItemBackground) + })); + } + + // Bind to the corresponding control components binding.tempoStepUp.setText(getStepUpPercentString(newStepSize)); binding.tempoStepDown.setText(getStepDownPercentString(newStepSize)); @@ -345,29 +461,6 @@ public class PlaybackParameterDialog extends DialogFragment { }); } - private void showPitchSemitonesOrPercent(final boolean semitones) { - binding.pitchPercentControl.setVisibility(semitones ? View.GONE : View.VISIBLE); - binding.pitchSemitoneControl.setVisibility(semitones ? View.VISIBLE : View.GONE); - - if (semitones) { - // Recalculate pitch percent when changing to semitone - // (as it could be an invalid semitone value) - final double newPitchPercent = calcValidPitch(pitchPercent); - - // If the values differ set the new pitch - if (this.pitchPercent != newPitchPercent) { - if (DEBUG) { - Log.d(TAG, "Bringing pitchPercent to correct corresponding semitone: " - + "currentPitchPercent = " + pitchPercent + ", " - + "newPitchPercent = " + newPitchPercent - ); - } - this.onPitchPercentSliderUpdated(newPitchPercent); - updateCallback(); - } - } - } - /*////////////////////////////////////////////////////////////////////////// // Sliders //////////////////////////////////////////////////////////////////////////*/ @@ -447,7 +540,7 @@ public class PlaybackParameterDialog extends DialogFragment { final double calcPitch = Math.max(MIN_PLAYBACK_VALUE, Math.min(MAX_PLAYBACK_VALUE, newPitch)); - if (!binding.adjustBySemitonesCheckbox.isChecked()) { + if (!isCurrentPitchControlModeSemitone()) { return calcPitch; } diff --git a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt new file mode 100644 index 000000000..50f875257 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt @@ -0,0 +1,26 @@ +package org.schabi.newpipe.util + +import android.content.Context +import android.graphics.drawable.Drawable +import androidx.annotation.AttrRes + +/** + * Utility class for resolving [Drawables](Drawable) + */ +class DrawableResolver { + companion object { + @JvmStatic + fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { + return androidx.core.content.ContextCompat.getDrawable( + context, + android.util.TypedValue().apply { + context.theme.resolveAttribute( + attrResId, + this, + true + ) + }.resourceId + ) + } + } +} diff --git a/app/src/main/res/layout/dialog_playback_parameter.xml b/app/src/main/res/layout/dialog_playback_parameter.xml index 640475f39..e402f4fb1 100644 --- a/app/src/main/res/layout/dialog_playback_parameter.xml +++ b/app/src/main/res/layout/dialog_playback_parameter.xml @@ -146,11 +146,59 @@ android:textColor="?attr/colorAccent" android:textStyle="bold" /> + + + + + + + + + + - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 792e6414b..af2921cca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -501,6 +501,8 @@ Step Tempo step Reset + Percent + Semitone In order to comply with the European General Data Protection Regulation (GDPR), we hereby draw your attention to NewPipe\'s privacy policy. Please read it carefully. \nYou must accept it to send us the bug report. From 20602889be38e38c25e6022f56be83860ef34313 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 4 Mar 2022 22:02:39 +0100 Subject: [PATCH 014/106] Added some doc and abstracted more methods --- .../helper/PlaybackParameterDialog.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 902222cc5..4ab8f9248 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -172,7 +172,7 @@ public class PlaybackParameterDialog extends DialogFragment { } /*////////////////////////////////////////////////////////////////////////// - // Control Views + // UI Initialization and Control //////////////////////////////////////////////////////////////////////////*/ private void initUI() { @@ -265,8 +265,7 @@ public class PlaybackParameterDialog extends DialogFragment { isChecked -> { if (!isChecked) { // when unchecked, slide back to the minimum of current tempo or pitch - setSliders(Math.min(pitchPercent, tempo)); - updateCallback(); + ensureHookIsValidAndUpdateCallBack(); } }); @@ -277,6 +276,8 @@ public class PlaybackParameterDialog extends DialogFragment { }); } + // -- General formatting -- + private void setText( final TextView textView, final DoubleFunction formatter, @@ -285,6 +286,8 @@ public class PlaybackParameterDialog extends DialogFragment { Objects.requireNonNull(textView).setText(formatter.apply(value)); } + // -- Steps -- + private void registerOnStepClickListener( final TextView stepTextView, final DoubleSupplier currentValueSupplier, @@ -310,6 +313,8 @@ public class PlaybackParameterDialog extends DialogFragment { }); } + // -- Pitch -- + private void setupPitchControlModeTextView( final boolean semitones, final TextView textView @@ -367,6 +372,9 @@ public class PlaybackParameterDialog extends DialogFragment { this.onPitchPercentSliderUpdated(newPitchPercent); updateCallback(); } + } else if (!binding.unhookCheckbox.isChecked()) { + // When changing to percent it's possible that tempo is != pitch + ensureHookIsValidAndUpdateCallBack(); } } @@ -377,6 +385,8 @@ public class PlaybackParameterDialog extends DialogFragment { PITCH_CTRL_MODE_PERCENT); } + // -- Steps (Set) -- + private void setupStepTextView( final double stepSizeValue, final TextView textView @@ -430,6 +440,8 @@ public class PlaybackParameterDialog extends DialogFragment { .getFloat(getString(R.string.adjustment_step_key), (float) DEFAULT_STEP); } + // -- Additional options -- + private void setAndUpdateSkipSilence(final boolean newSkipSilence) { this.skipSilence = newSkipSilence; binding.skipSilenceCheckbox.setChecked(newSkipSilence); @@ -461,6 +473,18 @@ public class PlaybackParameterDialog extends DialogFragment { }); } + /** + * Ensures that the slider hook is valid and if not sets and updates the sliders accordingly. + *
+ * You have to ensure by yourself that the hooking is active. + */ + private void ensureHookIsValidAndUpdateCallBack() { + if (tempo != pitchPercent) { + setSliders(Math.min(tempo, pitchPercent)); + updateCallback(); + } + } + /*////////////////////////////////////////////////////////////////////////// // Sliders //////////////////////////////////////////////////////////////////////////*/ From 1b8c517e3ea1924787eeff075a575414a5f3b544 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 4 Mar 2022 22:21:17 +0100 Subject: [PATCH 015/106] Removed unused strings --- app/src/main/res/values/strings.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index af2921cca..1f87ae9fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -497,9 +497,7 @@ Pitch Unhook (may cause distortion) Fast-forward during silence - Adjust pitch by musical semitones Step - Tempo step Reset Percent Semitone From 44dada9e60b23f500c3904af8578a874e78c0c5a Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 6 Mar 2022 16:10:42 +0100 Subject: [PATCH 016/106] Use better Kotlin syntax From the PR review --- .../schabi/newpipe/local/feed/FeedFragment.kt | 2 +- .../schabi/newpipe/util/DrawableResolver.kt | 29 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index e8e78feda..55810284f 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -75,7 +75,7 @@ import org.schabi.newpipe.local.feed.item.StreamItem import org.schabi.newpipe.local.feed.service.FeedLoadService import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.util.DeviceUtils -import org.schabi.newpipe.util.DrawableResolver.Companion.resolveDrawable +import org.schabi.newpipe.util.DrawableResolver.resolveDrawable import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountStreams diff --git a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt index 50f875257..ccc9e7dd4 100644 --- a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt +++ b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt @@ -2,25 +2,24 @@ package org.schabi.newpipe.util import android.content.Context import android.graphics.drawable.Drawable +import android.util.TypedValue import androidx.annotation.AttrRes /** * Utility class for resolving [Drawables](Drawable) */ -class DrawableResolver { - companion object { - @JvmStatic - fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { - return androidx.core.content.ContextCompat.getDrawable( - context, - android.util.TypedValue().apply { - context.theme.resolveAttribute( - attrResId, - this, - true - ) - }.resourceId - ) - } +object DrawableResolver { + @JvmStatic + fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { + return androidx.core.content.ContextCompat.getDrawable( + context, + TypedValue().apply { + context.theme.resolveAttribute( + attrResId, + this, + true + ) + }.resourceId + ) } } From b9190eddfe1563cc5269caf2ca90a997db85a920 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Mon, 7 Mar 2022 20:30:25 +0100 Subject: [PATCH 017/106] Update DrawableResolver.kt Nicer import :wink: --- app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt index ccc9e7dd4..8a728bfbf 100644 --- a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt +++ b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.drawable.Drawable import android.util.TypedValue import androidx.annotation.AttrRes +import androidx.core.content.ContextCompat /** * Utility class for resolving [Drawables](Drawable) @@ -11,7 +12,7 @@ import androidx.annotation.AttrRes object DrawableResolver { @JvmStatic fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { - return androidx.core.content.ContextCompat.getDrawable( + return ContextCompat.getDrawable( context, TypedValue().apply { context.theme.resolveAttribute( From 0f551baf3729121dadc0597d615aab58ea13e941 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Wed, 16 Mar 2022 14:53:33 +0100 Subject: [PATCH 018/106] Refactored code --- .../helper/PlaybackParameterDialog.java | 24 +++++++++---------- .../player/helper/PlayerSemitoneHelper.java | 9 +++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 4ab8f9248..26caa1b20 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -44,8 +44,8 @@ public class PlaybackParameterDialog extends DialogFragment { private static final String TAG = "PlaybackParameterDialog"; // Minimum allowable range in ExoPlayer - private static final double MIN_PLAYBACK_VALUE = 0.10f; - private static final double MAX_PLAYBACK_VALUE = 3.00f; + private static final double MIN_PITCH_OR_SPEED = 0.10f; + private static final double MAX_PITCH_OR_SPEED = 3.00f; private static final boolean PITCH_CTRL_MODE_PERCENT = false; private static final boolean PITCH_CTRL_MODE_SEMITONE = true; @@ -62,8 +62,8 @@ public class PlaybackParameterDialog extends DialogFragment { private static final boolean DEFAULT_SKIP_SILENCE = false; private static final SliderStrategy QUADRATIC_STRATEGY = new SliderStrategy.Quadratic( - MIN_PLAYBACK_VALUE, - MAX_PLAYBACK_VALUE, + MIN_PITCH_OR_SPEED, + MAX_PITCH_OR_SPEED, 1.00f, 10_000); @@ -177,10 +177,10 @@ public class PlaybackParameterDialog extends DialogFragment { private void initUI() { // Tempo - setText(binding.tempoMinimumText, PlayerHelper::formatSpeed, MIN_PLAYBACK_VALUE); - setText(binding.tempoMaximumText, PlayerHelper::formatSpeed, MAX_PLAYBACK_VALUE); + setText(binding.tempoMinimumText, PlayerHelper::formatSpeed, MIN_PITCH_OR_SPEED); + setText(binding.tempoMaximumText, PlayerHelper::formatSpeed, MAX_PITCH_OR_SPEED); - binding.tempoSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PLAYBACK_VALUE)); + binding.tempoSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PITCH_OR_SPEED)); setAndUpdateTempo(tempo); binding.tempoSeekbar.setOnSeekBarChangeListener( getTempoOrPitchSeekbarChangeListener( @@ -215,10 +215,10 @@ public class PlaybackParameterDialog extends DialogFragment { changePitchControlMode(isCurrentPitchControlModeSemitone()); // Pitch - Percent - setText(binding.pitchPercentMinimumText, PlayerHelper::formatPitch, MIN_PLAYBACK_VALUE); - setText(binding.pitchPercentMaximumText, PlayerHelper::formatPitch, MAX_PLAYBACK_VALUE); + setText(binding.pitchPercentMinimumText, PlayerHelper::formatPitch, MIN_PITCH_OR_SPEED); + setText(binding.pitchPercentMaximumText, PlayerHelper::formatPitch, MAX_PITCH_OR_SPEED); - binding.pitchPercentSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PLAYBACK_VALUE)); + binding.pitchPercentSeekbar.setMax(QUADRATIC_STRATEGY.progressOf(MAX_PITCH_OR_SPEED)); setAndUpdatePitch(pitchPercent); binding.pitchPercentSeekbar.setOnSeekBarChangeListener( getTempoOrPitchSeekbarChangeListener( @@ -557,12 +557,12 @@ public class PlaybackParameterDialog extends DialogFragment { } private double calcValidTempo(final double newTempo) { - return Math.max(MIN_PLAYBACK_VALUE, Math.min(MAX_PLAYBACK_VALUE, newTempo)); + return Math.max(MIN_PITCH_OR_SPEED, Math.min(MAX_PITCH_OR_SPEED, newTempo)); } private double calcValidPitch(final double newPitch) { final double calcPitch = - Math.max(MIN_PLAYBACK_VALUE, Math.min(MAX_PLAYBACK_VALUE, newPitch)); + Math.max(MIN_PITCH_OR_SPEED, Math.min(MAX_PITCH_OR_SPEED, newPitch)); if (!isCurrentPitchControlModeSemitone()) { return calcPitch; diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java index abbcc2c82..f3a71d7cd 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerSemitoneHelper.java @@ -9,7 +9,7 @@ package org.schabi.newpipe.player.helper; * */ public final class PlayerSemitoneHelper { - public static final int TONES = 12; + public static final int SEMITONE_COUNT = 12; private PlayerSemitoneHelper() { // No impl @@ -24,14 +24,15 @@ public final class PlayerSemitoneHelper { } public static double semitonesToPercent(final int semitones) { - return Math.pow(2, ensureSemitonesInRange(semitones) / (double) TONES); + return Math.pow(2, ensureSemitonesInRange(semitones) / (double) SEMITONE_COUNT); } public static int percentToSemitones(final double percent) { - return ensureSemitonesInRange((int) Math.round(TONES * Math.log(percent) / Math.log(2))); + return ensureSemitonesInRange( + (int) Math.round(SEMITONE_COUNT * Math.log(percent) / Math.log(2))); } private static int ensureSemitonesInRange(final int semitones) { - return Math.max(-TONES, Math.min(TONES, semitones)); + return Math.max(-SEMITONE_COUNT, Math.min(SEMITONE_COUNT, semitones)); } } From 1dc146322c5666f2a4af9f9d14b5f2aa56626b32 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Thu, 17 Mar 2022 18:34:44 +0100 Subject: [PATCH 019/106] Merged ``DrawableResolver`` into ``ThemeHelper`` --- .../schabi/newpipe/local/feed/FeedFragment.kt | 2 +- .../helper/PlaybackParameterDialog.java | 2 +- .../schabi/newpipe/util/DrawableResolver.kt | 26 ------------------- .../org/schabi/newpipe/util/ThemeHelper.java | 18 +++++++++++++ 4 files changed, 20 insertions(+), 28 deletions(-) delete mode 100644 app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt index 55810284f..b291aa035 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt @@ -75,10 +75,10 @@ import org.schabi.newpipe.local.feed.item.StreamItem import org.schabi.newpipe.local.feed.service.FeedLoadService import org.schabi.newpipe.local.subscription.SubscriptionManager import org.schabi.newpipe.util.DeviceUtils -import org.schabi.newpipe.util.DrawableResolver.resolveDrawable import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.NavigationHelper import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountStreams +import org.schabi.newpipe.util.ThemeHelper.resolveDrawable import org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout import java.time.OffsetDateTime import java.util.function.Consumer diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 26caa1b20..62446b50e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -2,8 +2,8 @@ package org.schabi.newpipe.player.helper; import static org.schabi.newpipe.ktx.ViewUtils.animateRotation; import static org.schabi.newpipe.player.Player.DEBUG; -import static org.schabi.newpipe.util.DrawableResolver.resolveDrawable; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; +import static org.schabi.newpipe.util.ThemeHelper.resolveDrawable; import android.app.Dialog; import android.content.Context; diff --git a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt b/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt deleted file mode 100644 index 8a728bfbf..000000000 --- a/app/src/main/java/org/schabi/newpipe/util/DrawableResolver.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.schabi.newpipe.util - -import android.content.Context -import android.graphics.drawable.Drawable -import android.util.TypedValue -import androidx.annotation.AttrRes -import androidx.core.content.ContextCompat - -/** - * Utility class for resolving [Drawables](Drawable) - */ -object DrawableResolver { - @JvmStatic - fun resolveDrawable(context: Context, @AttrRes attrResId: Int): Drawable? { - return ContextCompat.getDrawable( - context, - TypedValue().apply { - context.theme.resolveAttribute( - attrResId, - this, - true - ) - }.resourceId - ) - } -} diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index 7c47d387f..7d06e57b6 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -23,9 +23,11 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.util.TypedValue; import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StyleRes; import androidx.appcompat.app.ActionBar; @@ -227,6 +229,22 @@ public final class ThemeHelper { return value.data; } + /** + * Resolves a {@link Drawable} by it's id. + * + * @param context Context + * @param attrResId Resource id + * @return the {@link Drawable} + */ + public static Drawable resolveDrawable( + @NonNull final Context context, + @AttrRes final int attrResId + ) { + final TypedValue typedValue = new TypedValue(); + context.getTheme().resolveAttribute(attrResId, typedValue, true); + return ContextCompat.getDrawable(context, typedValue.resourceId); + } + private static String getSelectedThemeKey(final Context context) { final String themeKey = context.getString(R.string.theme_key); final String defaultTheme = context.getResources().getString(R.string.default_theme_value); From a311519314085d5e79e1a55afc7c16dc744cb57b Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 16 Apr 2022 21:24:01 +0200 Subject: [PATCH 020/106] Fix merge conflicts --- .../player/helper/PlaybackParameterDialog.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 62446b50e..2d1461aaf 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -27,6 +27,7 @@ import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; import org.schabi.newpipe.databinding.DialogPlaybackParameterBinding; import org.schabi.newpipe.player.Player; +import org.schabi.newpipe.util.SimpleOnSeekBarChangeListener; import org.schabi.newpipe.util.SliderStrategy; import java.util.HashMap; @@ -37,6 +38,8 @@ import java.util.function.DoubleConsumer; import java.util.function.DoubleFunction; import java.util.function.DoubleSupplier; +import javax.annotation.Nonnull; + import icepick.Icepick; import icepick.State; @@ -493,25 +496,16 @@ public class PlaybackParameterDialog extends DialogFragment { final SliderStrategy sliderStrategy, final DoubleConsumer newValueConsumer ) { - return new SeekBar.OnSeekBarChangeListener() { + return new SimpleOnSeekBarChangeListener() { @Override - public void onProgressChanged(final SeekBar seekBar, final int progress, + public void onProgressChanged(@Nonnull final SeekBar seekBar, + final int progress, final boolean fromUser) { if (fromUser) { // ensure that the user triggered the change newValueConsumer.accept(sliderStrategy.valueOf(progress)); updateCallback(); } } - - @Override - public void onStartTrackingTouch(final SeekBar seekBar) { - // Do nothing - } - - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - // Do nothing - } }; } From 4904b48f5c26358f74917d0c6a7b0541d91cd9d3 Mon Sep 17 00:00:00 2001 From: ZiyanZHANG <2227437462@qq.com> Date: Sun, 17 Apr 2022 18:15:13 +0800 Subject: [PATCH 021/106] Update PlayQueueActivity.java --- .../java/org/schabi/newpipe/player/PlayQueueActivity.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java index 53e6ce591..676d63458 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java +++ b/app/src/main/java/org/schabi/newpipe/player/PlayQueueActivity.java @@ -97,7 +97,10 @@ public final class PlayQueueActivity extends AppCompatActivity getMenuInflater().inflate(R.menu.menu_play_queue, m); getMenuInflater().inflate(R.menu.menu_play_queue_bg, m); onMaybeMuteChanged(); - onPlaybackParameterChanged(player.getPlaybackParameters()); + // to avoid null reference + if (player != null) { + onPlaybackParameterChanged(player.getPlaybackParameters()); + } return true; } From 8ea98b64aa81ac15f3d01e2764be38b50220644e Mon Sep 17 00:00:00 2001 From: LingYinTianMeng <2632252014@qq.com> Date: Sun, 17 Apr 2022 22:23:03 +0800 Subject: [PATCH 022/106] fix issue #7563 --- .../local/playlist/LocalPlaylistFragment.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java index 0eb56d716..7cd2a3ec1 100644 --- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java @@ -414,14 +414,21 @@ public class LocalPlaylistFragment extends BaseLocalListFragment streamStatesIter = recordManager .loadLocalStreamStateBatch(playlist).blockingGet().iterator(); - while (playlistIter.hasNext()) { final PlaylistStreamEntry playlistItem = playlistIter.next(); final int indexInHistory = Collections.binarySearch(historyStreamIds, playlistItem.getStreamId()); - - final boolean hasState = streamStatesIter.next() != null; - if (indexInHistory < 0 || hasState) { + final StreamStateEntity streamStateEntity = streamStatesIter.next(); + final long duration = playlistItem.toStreamInfoItem().getDuration(); + boolean isFinished = false; + if (streamStateEntity != null) { + isFinished = streamStateEntity.isFinished(duration); + } + final boolean isNotWatchedItem = (streamStateEntity != null + && !isFinished); + if (indexInHistory < 0) { + notWatchedItems.add(playlistItem); + } else if (isNotWatchedItem) { notWatchedItems.add(playlistItem); } else if (!thumbnailVideoRemoved && playlistManager.getPlaylistThumbnail(playlistId) From 127a27315e3c813d0d323f3471b4b51fcd94ee3f Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Mon, 18 Apr 2022 22:05:42 +0800 Subject: [PATCH 023/106] Fix keyboard showing after the search box acquiring focus (#8227) * Fix keyboard showing after the search box acquiring focus * Fix the underlying problem as described in the issue #7647 --- .../java/org/schabi/newpipe/util/KeyboardUtil.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java b/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java index 71c0d3944..a709dc32e 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java +++ b/app/src/main/java/org/schabi/newpipe/util/KeyboardUtil.java @@ -24,7 +24,19 @@ public final class KeyboardUtil { if (editText.requestFocus()) { final InputMethodManager imm = ContextCompat.getSystemService(activity, InputMethodManager.class); - imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED); + if (!imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED)) { + /* + * Sometimes the keyboard can't be shown because Android's ImeFocusController is in + * a incorrect state e.g. when animations are disabled or the unfocus event of the + * previous view arrives in the wrong moment (see #7647 for details). + * The invalid state can be fixed by to re-focusing the editText. + */ + editText.clearFocus(); + editText.requestFocus(); + + // Try again + imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED); + } } } From ec5cfe001903d8790015648d75ef226bb1eadbe0 Mon Sep 17 00:00:00 2001 From: Nickoriginal <85299944+Nickoriginal@users.noreply.github.com> Date: Wed, 20 Apr 2022 16:15:27 +0300 Subject: [PATCH 024/106] Update USER_AGENT in DownloaderImpl --- app/src/main/java/org/schabi/newpipe/DownloaderImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java index fde991655..1a3a8adee 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java +++ b/app/src/main/java/org/schabi/newpipe/DownloaderImpl.java @@ -43,7 +43,7 @@ import static org.schabi.newpipe.MainActivity.DEBUG; public final class DownloaderImpl extends Downloader { public static final String USER_AGENT - = "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"; + = "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0"; public static final String YOUTUBE_RESTRICTED_MODE_COOKIE_KEY = "youtube_restricted_mode_key"; public static final String YOUTUBE_RESTRICTED_MODE_COOKIE = "PREF=f2=8000000"; From 047fe21c143fd945de34aa01c5efa4df033cb977 Mon Sep 17 00:00:00 2001 From: kt programs Date: Sat, 30 Apr 2022 17:43:30 +0800 Subject: [PATCH 025/106] Fix hiding player controls when playing from media button DefaultControlDispatcher was removed in ExoPlayer 2.16.0, so the class extending it that handled play/pause was removed in #8020. The new solution is to use an instance of ForwardingPlayer. Call sessionConnector.setPlayer with an instance of ForwardingPlayer that overrides play() and pause() and calls the callback methods. --- .../newpipe/player/helper/MediaSessionManager.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index c12ba754a..a8735dc08 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -13,6 +13,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.media.session.MediaButtonReceiver; +import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; @@ -55,7 +56,17 @@ public class MediaSessionManager { sessionConnector = new MediaSessionConnector(mediaSession); sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, callback)); - sessionConnector.setPlayer(player); + sessionConnector.setPlayer(new ForwardingPlayer(player) { + @Override + public void play() { + callback.play(); + } + + @Override + public void pause() { + callback.pause(); + } + }); } @Nullable From 173b6c3f00df02e64151ee642323205400d412f2 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sat, 30 Apr 2022 21:46:06 +0200 Subject: [PATCH 026/106] Fix wrong NonNull --- .../schabi/newpipe/player/helper/PlaybackParameterDialog.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java index 2d1461aaf..7220335d1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlaybackParameterDialog.java @@ -38,8 +38,6 @@ import java.util.function.DoubleConsumer; import java.util.function.DoubleFunction; import java.util.function.DoubleSupplier; -import javax.annotation.Nonnull; - import icepick.Icepick; import icepick.State; @@ -498,7 +496,7 @@ public class PlaybackParameterDialog extends DialogFragment { ) { return new SimpleOnSeekBarChangeListener() { @Override - public void onProgressChanged(@Nonnull final SeekBar seekBar, + public void onProgressChanged(@NonNull final SeekBar seekBar, final int progress, final boolean fromUser) { if (fromUser) { // ensure that the user triggered the change From 88f0325ee5405bc7519047993e8603084520e537 Mon Sep 17 00:00:00 2001 From: Tobias <72496742+Seven-t7@users.noreply.github.com> Date: Sat, 30 Apr 2022 20:15:33 -0500 Subject: [PATCH 027/106] I love Brazil!!! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sério mesmo? Você está enlouquecendo! --- app/src/main/res/values-pt-rBR/strings.xml | 48 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 0850034f6..6c1f81d15 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -711,4 +711,50 @@ Conexão de rede necessária As notificações estão desativadas Seja notificado - \ No newline at end of file + SponsorBlock + Ver site + Veja o site oficial do SponsorBlock. + Pular patrocinadores + Use a API SponsorBlock para pular automaticamente os patrocinadores nos vídeos. Atualmente, isso só funciona para vídeos do YouTube. + URL da API + A URL a ser usado ao consultar a API do SponsorBlock. Isso deve ser definido para que SponsorBlock funcione. + Notificar quando os patrocinadores forem ignorados + Mostre uma notificação de brinde quando um patrocinador for ignorado automaticamente. + Ver Política de Privacidade + Veja a política de privacidade do SponsorBlock. + Este é o URL que será consultado quando o aplicativo precisar saber quais partes de um vídeo devem ser ignoradas.\n\nVocê pode definir o URL oficial clicando na opção \'Usar oficial\' abaixo, embora seja altamente recomendável que você veja a política de privacidade do SponsorBlock antes de usá-lo. + Política de privacidade do SponsorBlock + https://sponsor.ajay.app/ + https://sponsor.ajay.app/api/ + https://gist.github.com/ajayyy/aa9f8ded2b573d4f73a3ffa0ef74f796 + Patrocinador ignorado + Intervalo/Introdução ignorado + Finalização/Créditos ignorado + Lembrete de Inscrição ignorado + Não-pago/Auto promoção ignorado + Sem música ignorado + Enrolação/Piadas ignorado + Pré-visualização/Recapitulação ignorado + Alternar patrocinadores + Limpar lista de canais permitidos + Limpe a lista de canais que o SponsorBlock irá ignorar. + SponsorBlock está ativado + SponsorBlock está desativado + A lista de canais permitidos foi limpa. + Canal adicionado à lista de canais permitidos + Canal removido da lista de canais permitidos + Tem certeza de que deseja excluir a lista de canais permitidos? + Tem certeza de que deseja redefinir as cores das categorias? + Cores Redefinidas. + Extras + Ajustes, correções e outros ajustes diversos pertencem aqui. + Configurações experimentais + Ativar player local (alfa) + Use um player embutido para reprodução local. Isso ainda está em desenvolvimento inicial, então provavelmente haverá muitos problemas, incluindo conflitos com o player existente + Forçar tela cheia automática + Se ativado, quando o dispositivo estiver no modo paisagem, ele forçará o modo de tela cheia, mesmo que o dispositivo seja um tablet ou TV. + Desativar relatório de erros + Impede que todas as telas de relatório de erros apareçam. Isso pode fazer com que o aplicativo se comporte inesperadamente. USE POR SUA CONTA E RISCO! + Mostrar contagem de não gostei + Utiliza a API ReturnYouTubeDislike para exibir o número de não gostei de um vídeo. Isso só funciona com vídeos do YouTube.\nAVISO: seu endereço IP ficará visível para a API. Use por sua conta e risco. + From 5a886b4ba05dd887d855667b2d950fdadf8450e6 Mon Sep 17 00:00:00 2001 From: Tobias <72496742+Seven-t7@users.noreply.github.com> Date: Sun, 1 May 2022 09:42:21 +0800 Subject: [PATCH 028/106] ;-; --- app/src/main/res/values-pt-rBR/strings.xml | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6c1f81d15..aad6113e9 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -712,6 +712,30 @@ As notificações estão desativadas Seja notificado SponsorBlock + SponsorBlock (Beta, serviço de terceiro) + Categorias do SponsorBlock + Personalize quais segmentos de vídeo pular, junto com suas marcações de cores na barra. + Redefinir cores + Ativar + Desativar + Cor da barra + Patrocinador + Promoção paga, referências pagas e anúncios diretos. Não deve ser usado para Auto promoção ou mensagens grátis para causas/criadores/sites/produtos que eles gostam. + Intervalo/Animação de Introdução + Um intervalo sem conteúdo real. Pode ser uma pausa, um quadro estático, uma animação repetitiva. Isso não deve ser usado em transições que contenham informação. + Finalização/Créditos + Créditos ou quando os cards finais do YouTube aparecem. Não deve ser usado para conclusões informativas. + Lembrete de interação (inscrever-se) + Quando houver um pequeno lembrete para curtir, inscrever-se ou segui-los no meio do conteúdo. Se é longo ou sobre algo em específico, deveria ser sob Não-pago/Auto promoção. + Não-pago/Auto promoção + Similar a "patrocinador", mas para auto promoções e segmentos não-pagos. Isso inclui seções sobre vendas, doações ou informações sobre com quem colaboraram. + Música: Seção sem música + Apenas para uso em vídeos musicais. Deve ser usado exclusivamente para seções de vídeos musicais que já não pertençam à outra categoria. + Enrolação/Piadas + Cenas tangenciais inseridas apenas por enrolação ou humor que não são necessárias para compreender o tópico principal do vídeo. Isto não deve incluir segmentos que fornecem contexto ou detalhes de segundo plano. + Pré-visualização/Recapitulação + Recapitulação rápida de episódios anteriores, ou uma prévia do que está chegando mais tarde no vídeo atual. Destinado a clipes editados juntos, não para resumos falados. + SponsorBlock Ver site Veja o site oficial do SponsorBlock. Pular patrocinadores @@ -730,7 +754,7 @@ Patrocinador ignorado Intervalo/Introdução ignorado Finalização/Créditos ignorado - Lembrete de Inscrição ignorado + Lembrete de inscrição ignorado Não-pago/Auto promoção ignorado Sem música ignorado Enrolação/Piadas ignorado @@ -738,20 +762,20 @@ Alternar patrocinadores Limpar lista de canais permitidos Limpe a lista de canais que o SponsorBlock irá ignorar. - SponsorBlock está ativado - SponsorBlock está desativado + SponsorBlock habilitando + SponsorBlock desabilitado A lista de canais permitidos foi limpa. Canal adicionado à lista de canais permitidos Canal removido da lista de canais permitidos Tem certeza de que deseja excluir a lista de canais permitidos? Tem certeza de que deseja redefinir as cores das categorias? - Cores Redefinidas. + Cores redefinidas. Extras Ajustes, correções e outros ajustes diversos pertencem aqui. Configurações experimentais Ativar player local (alfa) Use um player embutido para reprodução local. Isso ainda está em desenvolvimento inicial, então provavelmente haverá muitos problemas, incluindo conflitos com o player existente - Forçar tela cheia automática + Forçar tela cheia automaticamente Se ativado, quando o dispositivo estiver no modo paisagem, ele forçará o modo de tela cheia, mesmo que o dispositivo seja um tablet ou TV. Desativar relatório de erros Impede que todas as telas de relatório de erros apareçam. Isso pode fazer com que o aplicativo se comporte inesperadamente. USE POR SUA CONTA E RISCO! From 25575ea8b22d52e3296ed8bc3a8175a808b5b667 Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Sun, 1 May 2022 08:26:44 +0200 Subject: [PATCH 029/106] use actual NewPipe Sponsorblock APK certificate fingerprint It can be retrived by running the following command: $ keytool -printcert -file CERT.RSA | grep 'SHA1' The fingerprint was still set to the one from the official NewPipe app. --- app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt b/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt index 21a9059e2..c07f307f2 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt @@ -22,7 +22,7 @@ import java.time.format.DateTimeFormatter object ReleaseVersionUtil { // Public key of the certificate that is used in NewPipe release versions private const val RELEASE_CERT_PUBLIC_KEY_SHA1 = - "B0:2E:90:7C:1C:D6:FC:57:C3:35:F0:88:D0:8F:50:5F:94:E4:D2:15" + "7F:46:0D:D0:6A:2D:A0:6B:57:B5:2C:ED:73:06:B7:87:43:90:66:A9" @JvmStatic fun isReleaseApk(): Boolean { From b2ace0878ca0a8b47d41f66bfb4552da460f49f3 Mon Sep 17 00:00:00 2001 From: Gilbert Gilb's Date: Sun, 1 May 2022 08:33:31 +0200 Subject: [PATCH 030/106] bring back upstream code for release APK check Upstream code checks whether the current APK was signed with the release key for various reasons: - in order to show/hide the "Updates" settings menu - in order to make the "Updates" settings menu searchable or not - in order to check/not check for updates at the application start This behavior was removed in NewPipe SponsorBlock fork, but it probably shouldn't have been: - the newer APK installation won't work if the locally installed APK wasn't signed with the same key - `isReleaseApk` function was still invoked in NewPipe SponsorBlock to allow searching "Updates" settings from settings menu. But as the fingerprint wasn't correct (see 25575ea8b22d), the update settings would not be searchable which is a bug - this is a requirement for F-Droid inclusion as they sign their APKs with their own keys (so the updater wouldn't work) and they explicitly forbid auto-updaters by policy (see also https://github.com/polymorphicshade/NewPipe/issues/8) --- app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt | 6 ++++++ .../schabi/newpipe/settings/MainSettingsFragment.java | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt b/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt index e9380c7b2..b9d1fe8f9 100644 --- a/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt +++ b/app/src/main/java/org/schabi/newpipe/NewVersionWorker.kt @@ -20,6 +20,7 @@ import org.schabi.newpipe.extractor.downloader.Response import org.schabi.newpipe.extractor.exceptions.ReCaptchaException import org.schabi.newpipe.util.ReleaseVersionUtil.coerceUpdateCheckExpiry import org.schabi.newpipe.util.ReleaseVersionUtil.isLastUpdateCheckExpired +import org.schabi.newpipe.util.ReleaseVersionUtil.isReleaseApk import org.schabi.newpipe.util.Version import java.io.IOException @@ -69,6 +70,11 @@ class NewVersionWorker( @Throws(IOException::class, ReCaptchaException::class) private fun checkNewVersion() { + // Check if the current apk is a github one or not. + if (!isReleaseApk()) { + return + } + val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext) // Check if the last request has happened a certain time ago // to reduce the number of API requests. diff --git a/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java index a3b131d75..3776d78f6 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java @@ -9,6 +9,7 @@ import androidx.annotation.NonNull; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; +import org.schabi.newpipe.util.ReleaseVersionUtil; public class MainSettingsFragment extends BasePreferenceFragment { public static final boolean DEBUG = MainActivity.DEBUG; @@ -21,6 +22,14 @@ public class MainSettingsFragment extends BasePreferenceFragment { setHasOptionsMenu(true); // Otherwise onCreateOptionsMenu is not called + // Check if the app is updatable + if (!ReleaseVersionUtil.isReleaseApk()) { + getPreferenceScreen().removePreference( + findPreference(getString(R.string.update_pref_screen_key))); + + defaultPreferences.edit().putBoolean(getString(R.string.update_app_key), false).apply(); + } + // Hide debug preferences in RELEASE build variant if (!DEBUG) { getPreferenceScreen().removePreference( From 8602cdadfb660f32328a33c658247cee165c6cfd Mon Sep 17 00:00:00 2001 From: Tobias <72496742+Seven-t7@users.noreply.github.com> Date: Sun, 1 May 2022 22:12:01 +1000 Subject: [PATCH 031/106] <3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correções na tradução e removido uma duplicata --- app/src/main/res/values-pt-rBR/strings.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index aad6113e9..54bf12103 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -711,7 +711,6 @@ Conexão de rede necessária As notificações estão desativadas Seja notificado - SponsorBlock SponsorBlock (Beta, serviço de terceiro) Categorias do SponsorBlock Personalize quais segmentos de vídeo pular, junto com suas marcações de cores na barra. @@ -736,7 +735,7 @@ Pré-visualização/Recapitulação Recapitulação rápida de episódios anteriores, ou uma prévia do que está chegando mais tarde no vídeo atual. Destinado a clipes editados juntos, não para resumos falados. SponsorBlock - Ver site + Visita website Veja o site oficial do SponsorBlock. Pular patrocinadores Use a API SponsorBlock para pular automaticamente os patrocinadores nos vídeos. Atualmente, isso só funciona para vídeos do YouTube. @@ -744,7 +743,7 @@ A URL a ser usado ao consultar a API do SponsorBlock. Isso deve ser definido para que SponsorBlock funcione. Notificar quando os patrocinadores forem ignorados Mostre uma notificação de brinde quando um patrocinador for ignorado automaticamente. - Ver Política de Privacidade + Ver política de privacidade Veja a política de privacidade do SponsorBlock. Este é o URL que será consultado quando o aplicativo precisar saber quais partes de um vídeo devem ser ignoradas.\n\nVocê pode definir o URL oficial clicando na opção \'Usar oficial\' abaixo, embora seja altamente recomendável que você veja a política de privacidade do SponsorBlock antes de usá-lo. Política de privacidade do SponsorBlock From 7e50eed95e25928cc4a40d9308ff38c216a3de0e Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 1 May 2022 20:50:37 +0200 Subject: [PATCH 032/106] Removed unused string resources --- app/src/main/res/values-ar/strings.xml | 3 --- app/src/main/res/values-b+zh+HANS+CN/strings.xml | 3 --- app/src/main/res/values-ca/strings.xml | 1 - app/src/main/res/values-ckb/strings.xml | 1 - app/src/main/res/values-cs/strings.xml | 3 --- app/src/main/res/values-de/strings.xml | 3 --- app/src/main/res/values-el/strings.xml | 3 --- app/src/main/res/values-es/strings.xml | 3 --- app/src/main/res/values-et/strings.xml | 3 --- app/src/main/res/values-eu/strings.xml | 3 --- app/src/main/res/values-fa/strings.xml | 3 --- app/src/main/res/values-fr/strings.xml | 3 --- app/src/main/res/values-gl/strings.xml | 2 -- app/src/main/res/values-he/strings.xml | 3 --- app/src/main/res/values-hu/strings.xml | 1 - app/src/main/res/values-ia/strings.xml | 1 - app/src/main/res/values-in/strings.xml | 3 --- app/src/main/res/values-it/strings.xml | 3 --- app/src/main/res/values-ja/strings.xml | 2 -- app/src/main/res/values-nb-rNO/strings.xml | 3 --- app/src/main/res/values-nl/strings.xml | 3 --- app/src/main/res/values-pl/strings.xml | 3 --- app/src/main/res/values-pt-rBR/strings.xml | 3 --- app/src/main/res/values-pt-rPT/strings.xml | 3 --- app/src/main/res/values-pt/strings.xml | 4 ---- app/src/main/res/values-ro/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 5 ----- app/src/main/res/values-sc/strings.xml | 3 --- app/src/main/res/values-sk/strings.xml | 4 ---- app/src/main/res/values-sv/strings.xml | 3 --- app/src/main/res/values-ta/strings.xml | 1 - app/src/main/res/values-te/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 3 --- app/src/main/res/values-uk/strings.xml | 4 ---- app/src/main/res/values-vi/strings.xml | 2 -- app/src/main/res/values-zh-rHK/strings.xml | 2 -- app/src/main/res/values-zh-rTW/strings.xml | 6 ------ 37 files changed, 101 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 3bb304848..e7da4611a 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -730,11 +730,8 @@ إظهار خطأ snackbar لم يتم العثور على مدير ملفات مناسب لهذا الإجراء. \nالرجاء تثبيت مدير ملفات متوافق مع Storage Access Framework. - يتم تشغيله في الخلفية تعليق مثبت LeakCanary غير متوفر - ضبط الصوت من خلال النغمات الموسيقية النصفية - خطوة الإيقاع الافتراضي ExoPlayer تغيير حجم الفاصل الزمني للتحميل (حاليا %s). قد تؤدي القيمة الأقل إلى تسريع تحميل الفيديو الأولي. تتطلب التغييرات إعادة تشغيل المشغل. تكوين إشعار مشغل البث الحالي diff --git a/app/src/main/res/values-b+zh+HANS+CN/strings.xml b/app/src/main/res/values-b+zh+HANS+CN/strings.xml index c5b9e9646..917016675 100644 --- a/app/src/main/res/values-b+zh+HANS+CN/strings.xml +++ b/app/src/main/res/values-b+zh+HANS+CN/strings.xml @@ -670,11 +670,8 @@ 找不到适合此操作的文件管理器。 \n请安装与存储访问框架(SAF)兼容的文件管理器。 NewPipe 遇到了一个错误,点击此处报告此错误 - 已经在后台播放 置顶评论 LeakCanary 不可用 - 以音乐半音调整音高 - 节奏步长 改变加载间隔的大小(当前%s),较低的值可以加快初始的视频加载速度,改变需要重启播放器。 ExoPlayer 默认 配置当前正在播放的串流的通知 diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 421139875..a42e68940 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -650,7 +650,6 @@ Inicia el reproductor principal en pantalla completa Llisqueu els elements per eliminar-los Si la rotació automàtica està bloquejada, no inicieu vídeos al mini reproductor, sinó que aneu directament al mode de pantalla completa. Podeu accedir igualment al mini reproductor sortint de pantalla completa - Ja s\'està reproduint en segon pla Notificació d\'informe d\'error Tancar abruptament el reproductor Comprovar si hi ha actualitzacions diff --git a/app/src/main/res/values-ckb/strings.xml b/app/src/main/res/values-ckb/strings.xml index f621b88bd..399d2360e 100644 --- a/app/src/main/res/values-ckb/strings.xml +++ b/app/src/main/res/values-ckb/strings.xml @@ -672,7 +672,6 @@ پیشاندانی ”کڕاش کردنی لێدەرەکە“ سازاندنی پەیامی کێشەیەک پشکنین بۆ نوێکردنەوە - وا لە پاشبنەمادا لێدەدرێت کێشە لە سکاڵا کردنی پەیام پەیامەکانی سکاڵاکردن لە کێشەکان بابەتە نوێیەکانی فیید diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 84c957f1c..9ba0d1e98 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -684,7 +684,6 @@ Vytvořit oznámení o chybě Kontrola aktualizací… Ukázat „Shodit přehrávač“ - Hraje již v pozadí Nové položky feedů Pro tuto akci nebyl nalezen žádný vhodný správce souborů. \nProsím, nainstalujte správce souborů kompatibilní se Storage Access Framework. @@ -698,7 +697,5 @@ Shodit přehrávač Změnit interval načítání (aktuálně %s). Menší hodnota může zrychlit počáteční načítání videa. Změna vyžaduje restart přehrávače. LeakCanary není dostupné - Upravit výšku tónů po půltónech - Krok tempa Výchozí ExoPlayer \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1b47fba2f..ffc501c63 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -684,12 +684,9 @@ \nBitte installiere einen Dateimanager oder versuche, \'%s\' in den Downloadeinstellungen zu deaktivieren.
Es wurde kein geeigneter Dateimanager für diese Aktion gefunden. \nBitte installiere einen Storage Access Framework kompatiblen Dateimanager. - Wird bereits im Hintergrund abgespielt Angehefteter Kommentar LeakCanary ist nicht verfügbar - Tonhöhe nach musikalischen Halbtönen anpassen Ändern der Größe des Ladeintervalls (derzeit %s). Ein niedrigerer Wert kann das anfängliche Laden des Videos beschleunigen. Änderungen erfordern einen Neustart des Players. - Geschwindigkeitsstufe ExoPlayer Standard Benachrichtigungen Benachrichtigen über neue abonnierbare Streams diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index b54b34d60..e202d2b34 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -682,11 +682,8 @@ \nΕγκαταστήστε έναν συμβατό με το Πλαίσιο Πρόσβασης Αποθήκευσης.
Το NewPipe παρουσίασε ένα σφάλμα. Πατήστε για αναφορά Εμφάνιση μιας snackbar σφάλματος - Αναπαράγεται ήδη στο παρασκήνιο Καρφιτσωμένο σχόλιο Το LeakCanary δεν είναι διαθέσιμο - Προσαρμόστε τον τόνο με βάση τα μουσικά ημιτόνια - Βήμα τέμπο Εξ\' ορισμού ExoPlayer Αλλάξτε το μέγεθος του διαστήματος φόρτωσης (επί του παρόντος είναι %s). Μια χαμηλότερη τιμή μπορεί να επιταχύνει την αρχική φόρτωση βίντεο. Οι αλλαγές απαιτούν επανεκκίνηση της εφαρμογής. Ειδοποιήσεις diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f386801e2..bb0decc9a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -686,12 +686,9 @@ No se encontró ningún gestor de archivos adecuado para esta acción. \nPor favor instale un gestor de archivos compatible con \"Sistema de Acceso al Almacenamiento\". Comentario fijado - Ya se reproduce en segundo plano LeakCanary no está disponible ExoPlayer valor por defecto - Paso de tempo Cambia el tamaño del intervalo de carga (actualmente %s). Un valor más bajo puede acelerar la carga inicial del vídeo. Los cambios requieren un reinicio del reproductor. - Ajustar el tono por semitonos musicales Notificaciones Nuevos streams Notificación del reproductor diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index d04834f8a..029ff9878 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -674,7 +674,6 @@ NewPipe töös tekkis viga, sellest teavitamiseks klõpsi Jooksuta meediamängija kokku Näita veateate akent - Meedia esitamine taustal toimib juba Teavitus vigadest Teavitused vigadest informeerimiseks Tekkis viga, vaata vastavat teadet @@ -709,6 +708,4 @@ Sa oled nüüd selle kanali tellija , Lülita kõik sisse - Reguleeri helikõrgust muusikaliste pooltoonide kaupa - Tempo samm \ No newline at end of file diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 1c710641e..d4bddf4a8 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -666,7 +666,6 @@ Gehitu bideo hau isatsari Erakutsi \"Itxi erreproduzigailua\" Prozesatzen... Itxoin mesedez - Atzeko planoan erreproduzitzen dagoeneko Erroreen txostenen jakinarazpena Jakinarazpenak erroreen berri emateko NewPipe-k errore bat aurkitu du, sakatu berri emateko @@ -695,8 +694,6 @@ Kanal honetara harpidetu zara , Txandakatu denak - Doitu tonua semitono musikalen arabera - Tempo urratsa Aldatu karga maiztasun tamaina (unean %s). Balio txikiago batek bideoaren hasierako karga azkartu dezake. Erreproduzigailuaren berrabiarazte bat behar du. Harpidetzen jario berriei buruz jakinarazi Ezabatu deskargatutako fitxategi guztiak biltegitik\? diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index d0f4d3d84..dac49883d 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -683,10 +683,7 @@ نیوپایپ به خطایی برخورد. برای گزارش، بزنید خطایی رخ داد. آگاهی را ببینید نظر سنجاق شده - در حال پخش در پس‌زمینه لیک‌کاناری موجود نیست - گام سرعت - تنظیم زیر و بم با شبه‌تن‌ها تغییر اندازهٔ بازهٔ بار (هم‌اکنون %s). مقداری پایین‌تر، می‌تواند بار کردن نخستین ویدیو را سرعت بخشد. تغییرها نیاز به یک آغاز دوبارهٔ پخش‌کننده دارند. پیش‌گزیدهٔ اگزوپلیر آگاهی‌ها diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4a4559477..1716cc06b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -685,11 +685,8 @@ Aucun gestionnaire de fichier approprié n\'a été trouvé pour cette action. \nVeuillez installer un gestionnaire de fichiers ou essayez de désactiver \'%s\' dans les paramètres de téléchargement. Commentaire épinglé - Une lecture est déjà en arrière-plan LeakCanary n\'est pas disponible Modifie la taille de l\'intervalle de chargement (actuellement %s). Une valeur plus faible peut accélérer le chargement initial des vidéos . - Règler la hauteur par demi-tons musicaux - Pas du tempo Valeur par défaut d’ExoPlayer Nouveaux flux Configurer la notification du flux en cours de lecture diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 52225b843..7b49adc6d 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -672,8 +672,6 @@ Enfileirado Procurar actualizacións Procurar manualmente novas versións - Axustar o ton do semitóns musicais - Paso do tempo A procurar actualizacións… A partir do Android 10, só o \'Sistema de Acceso ao Almacenamento\' está soportado Cambia o tamaño do intervalo de carga (actualmente %s). Un valor menor pode acelerar o carregamento do vídeo. Cambios poden precisar un reinicio do reprodutor. diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index a0e6c32a9..4d4350f07 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -706,11 +706,8 @@ התראת דיווח שגיאה לא נמצאו מנהלי קבצים שמתאימים לפעולה הזאת. \nנא להתקין מנהל קבצים שתומך בתשתית גישה לאחסון. - כבר מתנגן ברקע הערה ננעצה LeakCanary אינה זמינה - התאמת גובה הצליל לפי חצאי טונים מוזיקליים - צעד מקצב ברירת מחדל של ExoPlayer שינוי גודל מרווח הטעינה (כרגע %s). ערך נמוך יותר עשוי להאיץ את טעינת הווידאו הראשונית. שינויים דורשים את הפעלת הנגן מחדש. התראות על תזרימים חדשים להרשמה diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index adaf6a8c0..e5457d3e1 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -683,6 +683,5 @@ %1$s letöltés törölve Rögzített megjegyzés - Már megy a lejátszás a háttérben LeakCanary nem elérhető \ No newline at end of file diff --git a/app/src/main/res/values-ia/strings.xml b/app/src/main/res/values-ia/strings.xml index e9d400be2..d5bc90e6f 100644 --- a/app/src/main/res/values-ia/strings.xml +++ b/app/src/main/res/values-ia/strings.xml @@ -229,7 +229,6 @@ Aperir con Suggestiones de recerca remote Cargar miniaturas - Notification Monstrante resultatos pro: %s Solmente alicun apparatos pote reproducer videos 2K/4K Initiar le reproductor principal in schermo plen diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 056cdfce4..1a88bb747 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -671,11 +671,8 @@ Tidak ada manajer file yang ditemukan untuk tindakan ini. \nMohon instal sebuah manajer file yang kompatibel dengan Storage Access Framework. Komentar dipin - Sudah diputar di latar belakang LeakCanary tidak tersedia - Langkah tempo Default ExoPlayer - Atur nada berdasarkan semitone musik Ubah ukuran interval pemuatan (saat ini %s). Sebuah nilai yang rendah mungkin dapat membuat pemuatan video awal lebih cepat. Membutuhkan sebuah pemulaian ulang pada pemain. Memuat detail stream… Frekuensi pemeriksaan diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 9f7b74d8e..9671f8617 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -683,12 +683,9 @@ Non è stato trovato alcun gestore di file appropriato per questa azione. \nInstallane uno compatibile con Storage Access Framework. Commento in primo piano - Già in riproduzione in sottofondo LeakCanary non è disponibile - Regola il tono secondo i semitoni musicali Predefinito ExoPlayer Cambia la dimensione dell\'intervallo da caricare (attualmente %s). Un valore basso può velocizzare il caricamento iniziale del video. La modifica richiede il riavvio del lettore. - Passo tempo Notifiche di nuove stream dalle iscrizioni Frequenza controllo Richiesta connessione alla rete diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a0699f229..9a15b25d1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -663,7 +663,6 @@ エラーが発生しました。通知をご覧ください NewPipe はエラーに遭遇しました。タップして報告 スナックバーにエラーを表示 - 既にバックグラウンドで再生されています 固定されたコメント この動作に適切なファイルマネージャが見つかりませんでした。 \nStorage Access Frameworkと互換性のあるファイルマネージャをインストールしてください。 @@ -673,7 +672,6 @@ エラー通知を作成 エラーを報告する通知 LeakCanaryが利用不可能です - 緩急音階 プレイヤー通知 ストリームの詳細を読み込んでいます… 登録チャンネルの新しいストリームについて通知する diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 92b24fbc8..b2829ba27 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -672,7 +672,6 @@ Viser et krasjalternativ ved bruk av avspilleren Det oppstod en feil. Sjekk merknaden. Festet kommentar - Spilles allerede i bakgrunnen Feilrapport-merknad Merknader for innrapportering av feil NewPipe-feil. Trykk for å rapportere. @@ -682,6 +681,4 @@ Installer en filbehandler som støtter lagringstilgangsrammeverk først. LeakCanary er ikke tilgjengelig ExoPlayer-forvalg - Juster toneart etter musikalske halvtoner - Tempo-steg \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index dd405963a..3a943d2ca 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -677,7 +677,6 @@ NewPipe meldt fout, tik voor bericht Foutmelding Maak een foutmelding - Speelt al op de achtergrond Korte foutmelding weergeven Er is geen geschikte bestandsbeheerder gevonden voor deze actie. \nInstalleer een bestandsbeheerder of probeer \'%s\' uit te schakelen in de download instellingen. @@ -686,7 +685,5 @@ Vastgemaakt commentaar LeakCanary is niet beschikbaar Verander de laad interval tijd (nu %s). Een lagere waarde kan het initiële laden van de video versnellen. De wijziging vereist een herstart van de speler. - Pas de toonhoogte aan met muzikale halve tonen - Tempo stap ExoPlayer standaard \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index cfa995212..6e2c95119 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -701,14 +701,11 @@ \nZainstaluj menedżer plików lub spróbuj wyłączyć „%s” w ustawieniach pobierania.
Nie znaleziono odpowiedniego menedżera plików dla tej akcji. \nZainstaluj menedżer plików zgodny z Storage Access Framework. - Już jest odtwarzane w tle Przypięty komentarz LeakCanary jest niedostępne Rozmiar interwału ładowania odtwarzania Zmień rozmiar interwału ładowania (aktualnie %s). Niższa wartość może przyspieszyć początkowe ładowanie wideo. Zmiany wymagają ponownego uruchomienia odtwarzacza domyślny ExoPlayera - Dostosuj wysokość półtonami - Krok tempa Powiadomienie odtwarzacza Skonfiguruj powiadomienie aktualnie odtwarzanego strumienia Uruchom sprawdzenie nowych strumieni diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 0850034f6..d19196c06 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -682,12 +682,9 @@ Mostrar um snackbar de erro Nenhum gerenciador de arquivos apropriado foi encontrado para esta ação. \nInstale um gerenciador de arquivos ou tente desativar \'%s\' nas configurações de download. - Já está tocando em segundo plano Comentário fixado O LeakCanary não está disponível - Passo do tempo Altere o tamanho do intervalo de carregamento (atualmente %s). Um valor menor pode acelerar o carregamento inicial do vídeo. As alterações exigem que o player reinicie. - Ajustar o tom por semitons musicais ExoPlayer padrão Notificação do reprodutor Configurar a notificação do fluxo da reprodução atual diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 43e782251..aa3862b6b 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -683,11 +683,8 @@ Nenhum gestor de ficheiros apropriado foi encontrado para esta ação. \nPor favor, instale um gestor de ficheiros compatível com o Storage Access Framework. Comentário fixado - Já está a reproduzir em segundo plano LeakCanary não está disponível Altere o tamanho do intervalo de carregamento (atualmente %s). Um valor menor pode acelerar o carregamento inicial do vídeo. Se fizer alterações é necessário reiniciar. - Ajustar o tom por semitons musicais - Passo do tempo Predefinido do ExoPlayer Notificações A carregar detalhes do fluxo… diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 9e1a80916..9563c9a6f 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -554,7 +554,6 @@ URL não reconhecido. Abrir com outra aplicação\? Enfileiramento automático Embaralhar - Notificação Apenas em Wi-Fi Nada Mudar de um reprodutor para outro pode substituir a sua fila @@ -683,13 +682,10 @@ \nPor favor, instale um gestor de ficheiros ou tente desativar \'%s\' nas configurações de descarregar.
Nenhum gestor de ficheiros apropriado foi encontrado para esta ação. \nPor favor, instale um gestor de ficheiros compatível com o Storage Access Framework. - Já está a reproduzir em segundo plano Comentário fixado LeakCanary não está disponível - Ajustar o tom por semitons musicais Predefinido do ExoPlayer Altere o tamanho do intervalo de carregamento (atualmente %s). Um valor menor pode acelerar o carregamento inicial do vídeo. Se fizer alterações é necessário reiniciar. - Passo do tempo Notificação do reprodutor Configurar a notificação da reprodução do fluxo atual Notificações diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index e83fc5462..67108b500 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -679,7 +679,6 @@ Procesarea.. Poate dura un moment Verifică dacă există actualizări Verifică manual dacă există versiuni noi - Se redă deja pe fundal Comentariu lipit Notificare cu raport de eroare Afișează opțiunea de a întrerupe atunci când utilizați playerul diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index fc4c03f42..2a16a4573 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -691,8 +691,6 @@ Проверить обновления Проверка обновлений… Новое на канале - Отчёт об ошибках плеера - Подробные отчёты об ошибках плеера вместо коротких всплывающих сообщений (полезно при диагностике проблем) Уведомления Новые видео Уведомления о новых видео в подписках @@ -718,11 +716,8 @@ \nПожалуйста, установите файловый менеджер, или попробуйте отключить \'%s\' в настройках загрузок. Для этого действия не найдено подходящего файлового менеджера. \nПожалуйста, установите файловый менеджер, совместимый со Storage Access Framework (SAF). - Уже проигрывается в фоне Закреплённый комментарий LeakCanary недоступна - Регулировка высоты тона по музыкальным полутонам - Шаг темпа Стандартное значение ExoPlayer Изменить размер интервала загрузки (сейчас %s). Меньшее значение может ускорить начальную загрузку видео. Изменение значения потребует перезапуска плеера. Загрузка деталей трансляции… diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 38a7c3303..7c6120832 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -683,10 +683,7 @@ \nPro praghere installa unu gestore de documentos cumpatìbile cun su \"Sistema de Atzessu a s\'Archiviatzione\". Faghe serrare su riproduidore Cummentu apicadu - Giai in riprodutzione in s\'isfundu LeakCanary no est a disponimentu - Règula s\'intonatzione in base a sos semitonos musicales - Passu de tempus Valore ExoPlayer predefinidu Muda sa mannària de s\'intervallu de carrigamentu (in custu momentu %s). Unu valore prus bassu diat pòdere allestrare su carrigamentu de incumintzu de su vìdeu. Sas modìficas tenent bisòngiu de torrare a allùghere su riproduidore. Cunfigura sa notìfica de su flussu in cursu de riprodutzione diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 9b7a62145..c47562bb0 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -647,8 +647,6 @@ Pri každom sťahovaní sa zobrazí výzva kam uložiť súbor Nie je nastavený adresár na sťahovanie, nastavte ho teraz Označiť ako videné - Načítavanie podrobností o kanáli… - Chyba pri zobrazení podrobností kanála Vypnuté Zapnuté Režim tabletu @@ -698,8 +696,6 @@ Zobrazí možnosť zlyhania pri používaní prehrávača Zobraziť krátke oznámenie chyby Oznámte chybu - Upraviť výšku poltónov - Krok tempa ExoPlayer preddefinovaný Zmeniť interval načítania (aktuálne %s). Menšia hodnota môže zvýšiť rýchlosť prvotného načítania videa. Zmena vyžaduje reštart. Upozornenia diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 63af6d4d6..b7e66a85b 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -682,13 +682,10 @@ \nInstallera en filhanterare eller testa att inaktivera \'%s\' i nedladdningsinställningarna. Ingen lämplig filhanterare hittades för denna åtgärd. \nInstallera en filhanterare som är kompatibel med Storage Access Framework. - Spelas redan i bakgrunden Fäst kommentar LeakCanary är inte tillgänglig - Justera tonhöjden med musikaliska halvtoner ExoPlayer standard Ändra inläsningsintervallets storlek (för närvarande %s). Ett lägre värde kan påskynda den första videoinläsningen. Ändringar kräver omstart av spelaren. - Temposteg Validera frekvens Kräver nätverksanslutning Alla nätverk diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index d7c920f2b..827da452a 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -253,7 +253,6 @@ இயக்குதலைத் மறுதொடர் நி நிகழ்வு ஏற்கனவே உள்ளது - அறிவிப்பு யூடியூபின் \"கட்டுப்பாடு பயன்முறை\"ஐ இயக்கு பாடல்கள் பிழைகளைப் புகாரளிக்க அறிவிப்புகள் diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml index 60542e0b6..3958e02b0 100644 --- a/app/src/main/res/values-te/strings.xml +++ b/app/src/main/res/values-te/strings.xml @@ -371,7 +371,6 @@ reCAPTCHA సవాలు reCAPTCHA సవాలు అభ్యర్థించబడింది ప్లేజాబితాను ఎంచుకోండి - ఇప్పటికే వెనుకగా ప్లే అవుతోంది డాటాబేసుని ఎగుమతిచేయుము యాప్ పునఃప్రారంభించబడిన తర్వాత భాష మారుతుంది ఛానెల్ వివరాలను చూపు diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 958dc5eeb..a9bbe30e5 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -682,13 +682,10 @@ Hata raporları için bildirimler Oynatıcı kullanırken çöktürme seçeneği gösterir Oynatıcıyı çöktür - Zaten arka planda oynuyor Sabitlenmiş yorum LeakCanary yok Yükleme ara boyutunu değiştir (şu anda %s). Düşük bir değer videonun ilk yüklenişini hızlandırabilir. Değişiklikler oynatıcının yeniden başlatılmasını gerektirir. ExoPlayer öntanımlısı - Tempo adımı - Perdeyi müzikal yarım tonlarla uyarla Yeni akış bildirimleri Bildirimler diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index f2a3e986e..0768f241b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -58,7 +58,6 @@ Завантаження Звіт про помилку Усе - Так Вимкнено Збій застосунку/інтерфейсу Ваш коментар (англійською): @@ -699,11 +698,8 @@ \nУстановіть файловий менеджер, сумісний зі Storage Access Framework. Показати панель помилок Створити сповіщення про помилку - Уже відтворюється у фоновому режимі Закріплений коментар LeakCanary недоступний - Крок темпу - Регулювання висоти звуку за музичними півтонами Типовий ExoPlayer Змінити розмір інтервалу завантаження (наразі %s). Менше значення може прискорити початкове завантаження відео. Зміни вимагають перезапуску програвача. Ви підписалися на цей канал diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 7ea1a1ed5..08bf7cae0 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -672,8 +672,6 @@ \nVui lòng cài đặt ứng dụng quản lý tệp hoặc tắt \'%s\' trong cài đặt tải xuống. Thay đổi kích thước khoảng thời gian tải (tầm khoảng %s). Để ở giá trị thấp hơn có thể sẽ tăng tốc độ tải video hơn ban đầu. Khởi động lại trình phát để áp dụng thay đổi. LeakCanary không khả dụng - Điều chỉnh cao độ theo nhạc nền âm nhạc - Nhịp độ tiếp theo ExoPlayer mặc định Bình luận được ghim \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 0e79f5a58..d527edc9b 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -603,10 +603,8 @@ %s 個新加串流 - 按樂音半度調整音高 新加串流通知 係咪要喺磁碟機上面消除晒全部下載咗嘅檔案? 通知已停用 單曲 - 節奏步伐 \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fd129fb6c..8b5a24661 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -539,7 +539,6 @@ 作用中播放器的佇列可能會被取代 從一個播放器切換到另一個可能會取代您的佇列 清除佇列前要求確認 - 通知 正在緩衝 隨機播放 @@ -638,8 +637,6 @@ 拖動列縮圖預覽 被創作者加心號 標記為已看過 - 正在載入頻道詳細資訊…… - 顯示頻道詳細資訊時發生錯誤 在圖片頂部顯示畢卡索彩色絲帶,指示其來源:紅色代表網路、藍色代表磁碟、綠色代表記憶體 顯示圖片指示器 遠端搜尋建議 @@ -674,12 +671,9 @@ NewPipe 遇到錯誤,點擊以回報 發生錯誤,請檢視通知 釘選的留言 - 已經在背景播放 LeakCanary 無法使用 - 步進時間 ExoPlayer 預設值 變更載入間隔大小(目前為 %s)。較低的值可能會提昇初始影片載入速度。變更需要重新啟動播放器。 - 按音樂半音調整音高 播放器通知 通知 正在載入串流詳細資訊…… From a67927c29ce5e3f60ed628fb307bda3333e28774 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 1 May 2022 21:56:49 +0200 Subject: [PATCH 033/106] Fix dialogs having incorrect color when opened via RouterActivity --- app/src/main/res/values/styles.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7c1265580..894e70bad 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -131,10 +131,6 @@ + + + + + - - +