Reduce complexity of feed preference code (#7657)

This commit is contained in:
ByteHamster 2025-02-15 20:25:10 +01:00 committed by GitHub
parent ceab86cbf8
commit 613dcc143f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 371 additions and 478 deletions

View File

@ -1,57 +1,27 @@
package de.danoeh.antennapod.ui.screen.feed.preferences;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.appbar.MaterialToolbar;
import androidx.fragment.app.Fragment;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.appbar.MaterialToolbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.event.settings.SkipIntroEndingChangedEvent;
import de.danoeh.antennapod.event.settings.SpeedPresetChangedEvent;
import de.danoeh.antennapod.event.settings.VolumeAdaptionChangedEvent;
import de.danoeh.antennapod.databinding.PlaybackSpeedFeedSettingDialogBinding;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedFilter;
import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.storage.database.DBReader;
import de.danoeh.antennapod.storage.database.DBWriter;
import de.danoeh.antennapod.ui.preferences.screen.synchronization.AuthenticationDialog;
import io.reactivex.Maybe;
import io.reactivex.MaybeOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* Container fragment for feed settings fragment.
* @see FeedSettingsPreferenceFragment for the actual preferences.
*/
public class FeedSettingsFragment extends Fragment {
private static final String TAG = "FeedSettingsFragment";
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
@ -105,435 +75,4 @@ public class FeedSettingsFragment extends Fragment {
disposable.dispose();
}
}
public static class FeedSettingsPreferenceFragment extends PreferenceFragmentCompat {
private static final String PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_AUTODOWNLOAD = "autoDownload";
private static final String PREF_SCREEN = "feedSettingsScreen";
private static final String PREF_AUTHENTICATION = "authentication";
private static final String PREF_AUTO_DELETE = "autoDelete";
private static final String PREF_CATEGORY_AUTO_DOWNLOAD = "autoDownloadCategory";
private static final String PREF_NEW_EPISODES_ACTION = "feedNewEpisodesAction";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final String PREF_AUTO_SKIP = "feedAutoSkip";
private static final String PREF_NOTIFICATION = "episodeNotification";
private static final String PREF_TAGS = "tags";
private Feed feed;
private Disposable disposable;
private FeedPreferences feedPreferences;
public static FeedSettingsPreferenceFragment newInstance(long feedId) {
FeedSettingsPreferenceFragment fragment = new FeedSettingsPreferenceFragment();
Bundle arguments = new Bundle();
arguments.putLong(EXTRA_FEED_ID, feedId);
fragment.setArguments(arguments);
return fragment;
}
boolean notificationPermissionDenied = false;
private final ActivityResultLauncher<String> enableNotificationsRequestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
SwitchPreferenceCompat pref = findPreference(PREF_NOTIFICATION);
pref.setChecked(true);
pref.callChangeListener(true);
return;
}
if (notificationPermissionDenied) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
return;
}
Toast.makeText(getContext(), R.string.notification_permission_denied, Toast.LENGTH_LONG).show();
notificationPermissionDenied = true;
});
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle state) {
final RecyclerView view = super.onCreateRecyclerView(inflater, parent, state);
// To prevent transition animation because of summary update
view.setItemAnimator(null);
view.setLayoutAnimation(null);
return view;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
// To prevent displaying partially loaded data
findPreference(PREF_SCREEN).setVisible(false);
long feedId = getArguments().getLong(EXTRA_FEED_ID);
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
Feed feed = DBReader.getFeed(feedId, false, 0, 0);
if (feed != null) {
emitter.onSuccess(feed);
} else {
emitter.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
feedPreferences = feed.getPreferences();
setupAutoDownloadPreference();
setupKeepUpdatedPreference();
setupAutoDeletePreference();
setupVolumeAdaptationPreferences();
setupNewEpisodesAction();
setupAuthentificationPreference();
setupEpisodeFilterPreference();
setupPlaybackSpeedPreference();
setupFeedAutoSkipPreference();
setupEpisodeNotificationPreference();
setupTags();
updateAutoDeleteSummary();
updateVolumeAdaptationValue();
updateAutoDownloadEnabled();
updateNewEpisodesAction();
if (feed.isLocalFeed()) {
findPreference(PREF_AUTHENTICATION).setVisible(false);
findPreference(PREF_CATEGORY_AUTO_DOWNLOAD).setVisible(false);
}
findPreference(PREF_SCREEN).setVisible(true);
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposable != null) {
disposable.dispose();
}
}
private void setupFeedAutoSkipPreference() {
findPreference(PREF_AUTO_SKIP).setOnPreferenceClickListener(preference -> {
new FeedPreferenceSkipDialog(getContext(),
feedPreferences.getFeedSkipIntro(),
feedPreferences.getFeedSkipEnding()) {
@Override
protected void onConfirmed(int skipIntro, int skipEnding) {
feedPreferences.setFeedSkipIntro(skipIntro);
feedPreferences.setFeedSkipEnding(skipEnding);
DBWriter.setFeedPreferences(feedPreferences);
EventBus.getDefault().post(
new SkipIntroEndingChangedEvent(feedPreferences.getFeedSkipIntro(),
feedPreferences.getFeedSkipEnding(),
feed.getId()));
}
}.show();
return false;
});
}
private void setupPlaybackSpeedPreference() {
Preference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED);
feedPlaybackSpeedPreference.setOnPreferenceClickListener(preference -> {
PlaybackSpeedFeedSettingDialogBinding viewBinding =
PlaybackSpeedFeedSettingDialogBinding.inflate(getLayoutInflater());
viewBinding.seekBar.setProgressChangedListener(speed ->
viewBinding.currentSpeedLabel.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
viewBinding.useGlobalCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
viewBinding.seekBar.setEnabled(!isChecked);
viewBinding.seekBar.setAlpha(isChecked ? 0.4f : 1f);
viewBinding.currentSpeedLabel.setAlpha(isChecked ? 0.4f : 1f);
viewBinding.skipSilenceFeed.setEnabled(!isChecked);
viewBinding.skipSilenceFeed.setAlpha(isChecked ? 0.4f : 1f);
});
float speed = feedPreferences.getFeedPlaybackSpeed();
FeedPreferences.SkipSilence skipSilence = feedPreferences.getFeedSkipSilence();
boolean isGlobal = speed == FeedPreferences.SPEED_USE_GLOBAL;
viewBinding.useGlobalCheckbox.setChecked(isGlobal);
viewBinding.seekBar.updateSpeed(isGlobal ? 1 : speed);
viewBinding.skipSilenceFeed.setChecked(!isGlobal
&& skipSilence == FeedPreferences.SkipSilence.AGGRESSIVE);
new MaterialAlertDialogBuilder(getContext())
.setTitle(R.string.playback_speed)
.setView(viewBinding.getRoot())
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
float newSpeed = viewBinding.useGlobalCheckbox.isChecked()
? FeedPreferences.SPEED_USE_GLOBAL : viewBinding.seekBar.getCurrentSpeed();
feedPreferences.setFeedPlaybackSpeed(newSpeed);
FeedPreferences.SkipSilence newSkipSilence;
if (viewBinding.useGlobalCheckbox.isChecked()) {
newSkipSilence = FeedPreferences.SkipSilence.GLOBAL;
} else if (viewBinding.skipSilenceFeed.isChecked()) {
newSkipSilence = FeedPreferences.SkipSilence.AGGRESSIVE;
} else {
newSkipSilence = FeedPreferences.SkipSilence.OFF;
}
feedPreferences.setFeedSkipSilence(newSkipSilence);
DBWriter.setFeedPreferences(feedPreferences);
EventBus.getDefault().post(new SpeedPresetChangedEvent(
feedPreferences.getFeedPlaybackSpeed(),
feed.getId(), feedPreferences.getFeedSkipSilence()));
})
.setNegativeButton(R.string.cancel_label, null)
.show();
return true;
});
}
private void setupEpisodeFilterPreference() {
findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
@Override
protected void onConfirmed(FeedFilter filter) {
feedPreferences.setFilter(filter);
DBWriter.setFeedPreferences(feedPreferences);
}
}.show();
return false;
});
}
private void setupAuthentificationPreference() {
findPreference(PREF_AUTHENTICATION).setOnPreferenceClickListener(preference -> {
new AuthenticationDialog(getContext(),
R.string.authentication_label, true,
feedPreferences.getUsername(), feedPreferences.getPassword()) {
@Override
protected void onConfirmed(String username, String password) {
feedPreferences.setUsername(username);
feedPreferences.setPassword(password);
Future<?> setPreferencesFuture = DBWriter.setFeedPreferences(feedPreferences);
new Thread(() -> {
try {
setPreferencesFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
FeedUpdateManager.getInstance().runOnce(getContext(), feed);
}, "RefreshAfterCredentialChange").start();
}
}.show();
return false;
});
}
private void setupAutoDeletePreference() {
findPreference(PREF_AUTO_DELETE).setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "global":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.GLOBAL);
break;
case "always":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.ALWAYS);
break;
case "never":
feedPreferences.setAutoDeleteAction(FeedPreferences.AutoDeleteAction.NEVER);
break;
default:
}
DBWriter.setFeedPreferences(feedPreferences);
updateAutoDeleteSummary();
return false;
});
}
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = findPreference(PREF_AUTO_DELETE);
switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL:
autoDeletePreference.setSummary(R.string.global_default);
autoDeletePreference.setValue("global");
break;
case ALWAYS:
autoDeletePreference.setSummary(R.string.feed_auto_download_always);
autoDeletePreference.setValue("always");
break;
case NEVER:
autoDeletePreference.setSummary(R.string.feed_auto_download_never);
autoDeletePreference.setValue("never");
break;
}
}
private void setupVolumeAdaptationPreferences() {
ListPreference volumeAdaptationPreference = findPreference("volumeReduction");
volumeAdaptationPreference.setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "off":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.OFF);
break;
case "light":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.LIGHT_REDUCTION);
break;
case "heavy":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.HEAVY_REDUCTION);
break;
case "light_boost":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.LIGHT_BOOST);
break;
case "medium_boost":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.MEDIUM_BOOST);
break;
case "heavy_boost":
feedPreferences.setVolumeAdaptionSetting(VolumeAdaptionSetting.HEAVY_BOOST);
break;
default:
}
DBWriter.setFeedPreferences(feedPreferences);
updateVolumeAdaptationValue();
EventBus.getDefault().post(
new VolumeAdaptionChangedEvent(feedPreferences.getVolumeAdaptionSetting(), feed.getId()));
return false;
});
}
private void updateVolumeAdaptationValue() {
ListPreference volumeAdaptationPreference = findPreference("volumeReduction");
switch (feedPreferences.getVolumeAdaptionSetting()) {
case OFF:
volumeAdaptationPreference.setValue("off");
break;
case LIGHT_REDUCTION:
volumeAdaptationPreference.setValue("light");
break;
case HEAVY_REDUCTION:
volumeAdaptationPreference.setValue("heavy");
break;
case LIGHT_BOOST:
volumeAdaptationPreference.setValue("light_boost");
break;
case MEDIUM_BOOST:
volumeAdaptationPreference.setValue("medium_boost");
break;
case HEAVY_BOOST:
volumeAdaptationPreference.setValue("heavy_boost");
break;
}
}
private void setupNewEpisodesAction() {
findPreference(PREF_NEW_EPISODES_ACTION).setOnPreferenceChangeListener((preference, newValue) -> {
int code = Integer.parseInt((String) newValue);
feedPreferences.setNewEpisodesAction(FeedPreferences.NewEpisodesAction.fromCode(code));
DBWriter.setFeedPreferences(feedPreferences);
updateNewEpisodesAction();
return false;
});
}
private void updateNewEpisodesAction() {
ListPreference newEpisodesAction = findPreference(PREF_NEW_EPISODES_ACTION);
newEpisodesAction.setValue("" + feedPreferences.getNewEpisodesAction().code);
switch (feedPreferences.getNewEpisodesAction()) {
case GLOBAL:
newEpisodesAction.setSummary(R.string.global_default);
break;
case ADD_TO_INBOX:
newEpisodesAction.setSummary(R.string.feed_new_episodes_action_add_to_inbox);
break;
case ADD_TO_QUEUE:
newEpisodesAction.setSummary(R.string.feed_new_episodes_action_add_to_queue);
break;
case NOTHING:
newEpisodesAction.setSummary(R.string.feed_new_episodes_action_nothing);
break;
default:
}
}
private void setupKeepUpdatedPreference() {
SwitchPreferenceCompat pref = findPreference("keepUpdated");
pref.setChecked(feedPreferences.getKeepUpdated());
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = Boolean.TRUE.equals(newValue);
feedPreferences.setKeepUpdated(checked);
DBWriter.setFeedPreferences(feedPreferences);
pref.setChecked(checked);
return false;
});
}
private void setupAutoDownloadPreference() {
findPreference(PREF_AUTODOWNLOAD).setOnPreferenceChangeListener((preference, newValue) -> {
switch ((String) newValue) {
case "global":
feedPreferences.setAutoDownload(FeedPreferences.AutoDownloadSetting.GLOBAL);
break;
case "enabled":
feedPreferences.setAutoDownload(FeedPreferences.AutoDownloadSetting.ENABLED);
break;
case "disabled":
feedPreferences.setAutoDownload(FeedPreferences.AutoDownloadSetting.DISABLED);
break;
default:
}
DBWriter.setFeedPreferences(feedPreferences);
updateAutoDownloadEnabled();
return false;
});
}
private void updateAutoDownloadEnabled() {
if (feed == null || feed.getPreferences() == null) {
return;
}
boolean enabled = feed.getPreferences().isAutoDownload(UserPreferences.isEnableAutodownloadGlobal());
findPreference(PREF_EPISODE_FILTER).setEnabled(enabled);
ListPreference autoDownloadPreference = findPreference(PREF_AUTODOWNLOAD);
switch (feedPreferences.getAutoDownload()) {
case GLOBAL:
if (feedPreferences.getAutoDownload() == FeedPreferences.AutoDownloadSetting.GLOBAL) {
autoDownloadPreference.setSummary(getString(R.string.global_default_with_value,
enabled ? getString(R.string.enabled) : getString(R.string.disabled)));
}
autoDownloadPreference.setValue("global");
break;
case ENABLED:
autoDownloadPreference.setSummary(R.string.enabled);
autoDownloadPreference.setValue("enabled");
break;
case DISABLED:
autoDownloadPreference.setSummary(R.string.disabled);
autoDownloadPreference.setValue("disabled");
break;
}
}
private void setupTags() {
findPreference(PREF_TAGS).setOnPreferenceClickListener(preference -> {
TagSettingsDialog.newInstance(Collections.singletonList(feedPreferences))
.show(getChildFragmentManager(), TagSettingsDialog.TAG);
return true;
});
}
private void setupEpisodeNotificationPreference() {
SwitchPreferenceCompat pref = findPreference(PREF_NOTIFICATION);
pref.setChecked(feedPreferences.getShowEpisodeNotification());
pref.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = Boolean.TRUE.equals(newValue);
if (checked && Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
enableNotificationsRequestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
return false;
}
feedPreferences.setShowEpisodeNotification(checked);
DBWriter.setFeedPreferences(feedPreferences);
pref.setChecked(checked);
return false;
});
}
}
}

View File

@ -0,0 +1,351 @@
package de.danoeh.antennapod.ui.screen.feed.preferences;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.ContextCompat;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.databinding.PlaybackSpeedFeedSettingDialogBinding;
import de.danoeh.antennapod.event.settings.SkipIntroEndingChangedEvent;
import de.danoeh.antennapod.event.settings.SpeedPresetChangedEvent;
import de.danoeh.antennapod.event.settings.VolumeAdaptionChangedEvent;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedFilter;
import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
import de.danoeh.antennapod.storage.database.DBReader;
import de.danoeh.antennapod.storage.database.DBWriter;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.preferences.screen.synchronization.AuthenticationDialog;
import io.reactivex.Maybe;
import io.reactivex.MaybeOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class FeedSettingsPreferenceFragment extends PreferenceFragmentCompat {
private static final String TAG = "FeedSettingsPrefFrag";
private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
private static final String PREF_EPISODE_FILTER = "episodeFilter";
private static final String PREF_AUTODOWNLOAD = "autoDownload";
private static final String PREF_SCREEN = "feedSettingsScreen";
private static final String PREF_AUTHENTICATION = "authentication";
private static final String PREF_AUTO_DELETE = "autoDelete";
private static final String PREF_CATEGORY_AUTO_DOWNLOAD = "autoDownloadCategory";
private static final String PREF_NEW_EPISODES_ACTION = "feedNewEpisodesAction";
private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed";
private static final String PREF_AUTO_SKIP = "feedAutoSkip";
private static final String PREF_NOTIFICATION = "episodeNotification";
private static final String PREF_TAGS = "tags";
private Feed feed;
private Disposable disposable;
private FeedPreferences feedPreferences;
public static FeedSettingsPreferenceFragment newInstance(long feedId) {
FeedSettingsPreferenceFragment fragment = new FeedSettingsPreferenceFragment();
Bundle arguments = new Bundle();
arguments.putLong(EXTRA_FEED_ID, feedId);
fragment.setArguments(arguments);
return fragment;
}
boolean notificationPermissionDenied = false;
private final ActivityResultLauncher<String> enableNotificationsRequestPermissionLauncher =
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
if (isGranted) {
SwitchPreferenceCompat pref = findPreference(PREF_NOTIFICATION);
pref.setChecked(true);
pref.callChangeListener(true);
return;
}
if (notificationPermissionDenied) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
return;
}
Toast.makeText(getContext(), R.string.notification_permission_denied, Toast.LENGTH_LONG).show();
notificationPermissionDenied = true;
});
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle state) {
final RecyclerView view = super.onCreateRecyclerView(inflater, parent, state);
// To prevent transition animation because of summary update
view.setItemAnimator(null);
view.setLayoutAnimation(null);
return view;
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.feed_settings);
// To prevent displaying partially loaded data
findPreference(PREF_SCREEN).setVisible(false);
long feedId = getArguments().getLong(EXTRA_FEED_ID);
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
Feed feed = DBReader.getFeed(feedId, false, 0, 0);
if (feed != null) {
emitter.onSuccess(feed);
} else {
emitter.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
feed = result;
feedPreferences = feed.getPreferences();
setupPreferences();
updateAutoDeleteSummary();
updateAutoDownloadEnabledSummary();
updateNewEpisodesActionSummary();
if (feed.isLocalFeed()) {
findPreference(PREF_AUTHENTICATION).setVisible(false);
findPreference(PREF_CATEGORY_AUTO_DOWNLOAD).setVisible(false);
}
findPreference(PREF_SCREEN).setVisible(true);
}, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
}
@Override
public void onDestroy() {
super.onDestroy();
if (disposable != null) {
disposable.dispose();
}
}
private void setupPreferences() {
findPreference(PREF_AUTO_SKIP).setOnPreferenceClickListener(preference -> {
new FeedPreferenceSkipDialog(getContext(),
feedPreferences.getFeedSkipIntro(), feedPreferences.getFeedSkipEnding()) {
@Override
protected void onConfirmed(int skipIntro, int skipEnding) {
feedPreferences.setFeedSkipIntro(skipIntro);
feedPreferences.setFeedSkipEnding(skipEnding);
DBWriter.setFeedPreferences(feedPreferences);
EventBus.getDefault().post(
new SkipIntroEndingChangedEvent(feedPreferences.getFeedSkipIntro(),
feedPreferences.getFeedSkipEnding(), feed.getId()));
}
}.show();
return false;
});
findPreference(PREF_FEED_PLAYBACK_SPEED).setOnPreferenceClickListener(this::showPlaybackSpeedDialog);
findPreference(PREF_EPISODE_FILTER).setOnPreferenceClickListener(preference -> {
new EpisodeFilterDialog(getContext(), feedPreferences.getFilter()) {
@Override
protected void onConfirmed(FeedFilter filter) {
feedPreferences.setFilter(filter);
DBWriter.setFeedPreferences(feedPreferences);
}
}.show();
return false;
});
findPreference(PREF_AUTHENTICATION).setOnPreferenceClickListener(preference -> {
new AuthenticationDialog(getContext(),
R.string.authentication_label, true,
feedPreferences.getUsername(), feedPreferences.getPassword()) {
@Override
protected void onConfirmed(String username, String password) {
feedPreferences.setUsername(username);
feedPreferences.setPassword(password);
Future<?> setPreferencesFuture = DBWriter.setFeedPreferences(feedPreferences);
new Thread(() -> {
try {
setPreferencesFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
FeedUpdateManager.getInstance().runOnce(getContext(), feed);
}, "RefreshAfterCredentialChange").start();
}
}.show();
return false;
});
findPreference(PREF_AUTO_DELETE).setOnPreferenceChangeListener((preference, newValue) -> {
feedPreferences.setAutoDeleteAction(
FeedPreferences.AutoDeleteAction.fromCode(Integer.parseInt((String) newValue)));
DBWriter.setFeedPreferences(feedPreferences);
updateAutoDeleteSummary();
return false;
});
ListPreference volumeAdaptationPreference = findPreference("volumeReduction");
volumeAdaptationPreference.setValue("" + feedPreferences.getVolumeAdaptionSetting().toInteger());
volumeAdaptationPreference.setOnPreferenceChangeListener((preference, newValue) -> {
VolumeAdaptionSetting newSetting = VolumeAdaptionSetting.fromInteger(Integer.parseInt((String) newValue));
feedPreferences.setVolumeAdaptionSetting(newSetting);
DBWriter.setFeedPreferences(feedPreferences);
volumeAdaptationPreference.setValue("" + feedPreferences.getVolumeAdaptionSetting().toInteger());
EventBus.getDefault().post(new VolumeAdaptionChangedEvent(newSetting, feed.getId()));
return false;
});
findPreference(PREF_NEW_EPISODES_ACTION).setOnPreferenceChangeListener((preference, newValue) -> {
int code = Integer.parseInt((String) newValue);
feedPreferences.setNewEpisodesAction(FeedPreferences.NewEpisodesAction.fromCode(code));
DBWriter.setFeedPreferences(feedPreferences);
updateNewEpisodesActionSummary();
return false;
});
SwitchPreferenceCompat keepUpdated = findPreference("keepUpdated");
keepUpdated.setChecked(feedPreferences.getKeepUpdated());
keepUpdated.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = Boolean.TRUE.equals(newValue);
feedPreferences.setKeepUpdated(checked);
DBWriter.setFeedPreferences(feedPreferences);
keepUpdated.setChecked(checked);
return false;
});
findPreference(PREF_AUTODOWNLOAD).setOnPreferenceChangeListener((preference, newValue) -> {
feedPreferences.setAutoDownload(
FeedPreferences.AutoDownloadSetting.fromInteger(Integer.parseInt((String) newValue)));
DBWriter.setFeedPreferences(feedPreferences);
updateAutoDownloadEnabledSummary();
return false;
});
findPreference(PREF_TAGS).setOnPreferenceClickListener(preference -> {
TagSettingsDialog.newInstance(Collections.singletonList(feedPreferences))
.show(getChildFragmentManager(), TagSettingsDialog.TAG);
return true;
});
SwitchPreferenceCompat notificationPreference = findPreference(PREF_NOTIFICATION);
notificationPreference.setChecked(feedPreferences.getShowEpisodeNotification());
notificationPreference.setOnPreferenceChangeListener((preference, newValue) -> {
boolean checked = Boolean.TRUE.equals(newValue);
if (checked && Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
enableNotificationsRequestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
return false;
}
feedPreferences.setShowEpisodeNotification(checked);
DBWriter.setFeedPreferences(feedPreferences);
notificationPreference.setChecked(checked);
return false;
});
}
private void updateAutoDeleteSummary() {
ListPreference autoDeletePreference = findPreference(PREF_AUTO_DELETE);
boolean isEnabledGlobally = feed.isLocalFeed()
? UserPreferences.isAutoDeleteLocal() : UserPreferences.isAutoDelete();
int globalStringResource = isEnabledGlobally
? R.string.feed_auto_download_always : R.string.feed_auto_download_never;
String summary = switch (feedPreferences.getAutoDeleteAction()) {
case GLOBAL -> getString(R.string.global_default_with_value, getString(globalStringResource));
case ALWAYS -> getString(R.string.feed_auto_download_always);
default -> getString(R.string.feed_auto_download_never);
};
autoDeletePreference.setSummary(summary);
autoDeletePreference.setValue("" + feedPreferences.getAutoDeleteAction().code);
}
private void updateNewEpisodesActionSummary() {
ListPreference newEpisodesAction = findPreference(PREF_NEW_EPISODES_ACTION);
newEpisodesAction.setValue("" + feedPreferences.getNewEpisodesAction().code);
int globalStringResource = switch (UserPreferences.getNewEpisodesAction()) {
case ADD_TO_INBOX -> R.string.feed_new_episodes_action_add_to_inbox;
case ADD_TO_QUEUE -> R.string.feed_new_episodes_action_add_to_queue;
default -> R.string.feed_new_episodes_action_nothing;
};
String summary = switch (feedPreferences.getNewEpisodesAction()) {
case GLOBAL -> getString(R.string.global_default_with_value, getString(globalStringResource));
case ADD_TO_INBOX -> getString(R.string.feed_new_episodes_action_add_to_inbox);
case ADD_TO_QUEUE -> getString(R.string.feed_new_episodes_action_add_to_queue);
default -> getString(R.string.feed_new_episodes_action_nothing);
};
newEpisodesAction.setSummary(summary);
}
private void updateAutoDownloadEnabledSummary() {
if (feed == null || feed.getPreferences() == null) {
return;
}
boolean enabled = feed.getPreferences().isAutoDownload(UserPreferences.isEnableAutodownloadGlobal());
findPreference(PREF_EPISODE_FILTER).setEnabled(enabled);
ListPreference autoDownloadPreference = findPreference(PREF_AUTODOWNLOAD);
String summary = switch (feedPreferences.getAutoDownload()) {
case GLOBAL -> getString(R.string.global_default_with_value,
getString(enabled ? R.string.enabled : R.string.disabled));
case ENABLED -> getString(R.string.enabled);
case DISABLED -> getString(R.string.disabled);
};
autoDownloadPreference.setSummary(summary);
autoDownloadPreference.setValue("" + feedPreferences.getAutoDownload().code);
}
private boolean showPlaybackSpeedDialog(Preference preference) {
PlaybackSpeedFeedSettingDialogBinding viewBinding =
PlaybackSpeedFeedSettingDialogBinding.inflate(getLayoutInflater());
viewBinding.seekBar.setProgressChangedListener(speed ->
viewBinding.currentSpeedLabel.setText(String.format(Locale.getDefault(), "%.2fx", speed)));
viewBinding.useGlobalCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
viewBinding.seekBar.setEnabled(!isChecked);
viewBinding.seekBar.setAlpha(isChecked ? 0.4f : 1f);
viewBinding.currentSpeedLabel.setAlpha(isChecked ? 0.4f : 1f);
viewBinding.skipSilenceFeed.setEnabled(!isChecked);
viewBinding.skipSilenceFeed.setAlpha(isChecked ? 0.4f : 1f);
});
float speed = feedPreferences.getFeedPlaybackSpeed();
FeedPreferences.SkipSilence skipSilence = feedPreferences.getFeedSkipSilence();
boolean isGlobal = speed == FeedPreferences.SPEED_USE_GLOBAL;
viewBinding.useGlobalCheckbox.setChecked(isGlobal);
viewBinding.seekBar.updateSpeed(isGlobal ? 1 : speed);
viewBinding.skipSilenceFeed.setChecked(!isGlobal
&& skipSilence == FeedPreferences.SkipSilence.AGGRESSIVE);
new MaterialAlertDialogBuilder(getContext())
.setTitle(R.string.playback_speed)
.setView(viewBinding.getRoot())
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
float newSpeed = viewBinding.useGlobalCheckbox.isChecked()
? FeedPreferences.SPEED_USE_GLOBAL : viewBinding.seekBar.getCurrentSpeed();
feedPreferences.setFeedPlaybackSpeed(newSpeed);
FeedPreferences.SkipSilence newSkipSilence;
if (viewBinding.useGlobalCheckbox.isChecked()) {
newSkipSilence = FeedPreferences.SkipSilence.GLOBAL;
} else if (viewBinding.skipSilenceFeed.isChecked()) {
newSkipSilence = FeedPreferences.SkipSilence.AGGRESSIVE;
} else {
newSkipSilence = FeedPreferences.SkipSilence.OFF;
}
feedPreferences.setFeedSkipSilence(newSkipSilence);
DBWriter.setFeedPreferences(feedPreferences);
EventBus.getDefault().post(new SpeedPresetChangedEvent(feedPreferences.getFeedPlaybackSpeed(),
feed.getId(), feedPreferences.getFeedSkipSilence()));
})
.setNegativeButton(R.string.cancel_label, null)
.show();
return true;
}
}

View File

@ -7,10 +7,11 @@
<item>@string/feed_auto_download_never</item>
</string-array>
<!-- Keep consistent with AutoDeleteAction -->
<string-array name="spnAutoDeleteValues">
<item>global</item>
<item>always</item>
<item>never</item>
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string-array name="spnEnableAutoDownloadItems">
@ -19,10 +20,11 @@
<item>@string/disabled</item>
</string-array>
<!-- Keep consistent with AutoDownloadSetting -->
<string-array name="spnEnableAutoDownloadValues">
<item>global</item>
<item>enabled</item>
<item>disabled</item>
<item>1</item>
<item>2</item>
<item>0</item>
</string-array>
<string-array name="spnVolumeAdaptationItems">
@ -34,13 +36,14 @@
<item>@string/feed_volume_boost_heavy</item>
</string-array>
<!-- Keep consistent with VolumeAdaptionSetting -->
<string-array name="spnVolumeAdaptationValues">
<item>heavy</item>
<item>light</item>
<item>off</item>
<item>light_boost</item>
<item>medium_boost</item>
<item>heavy_boost</item>
<item>2</item>
<item>1</item>
<item>0</item>
<item>3</item>
<item>4</item>
<item>5</item>
</string-array>
<string-array name="feed_refresh_interval_entries">