content: 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.rxjava3.core.Maybe;
  import io.reactivex.rxjava3.core.MaybeOnSubscribe;
  import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
  import io.reactivex.rxjava3.disposables.Disposable;
  import io.reactivex.rxjava3.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 = "includeAutoDownload";
      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();
              updateNewEpisodesActionSummary();
              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() {
          if (feed == null || feed.getPreferences() == null) {
              return;
          }
          ListPreference newEpisodesAction = findPreference(PREF_NEW_EPISODES_ACTION);
          boolean isAutoDownload = feed.getPreferences().isAutoDownload(UserPreferences.isEnableAutodownloadGlobal());
          if (isAutoDownload && !feed.isLocalFeed()) {
              newEpisodesAction.setEnabled(false);
              newEpisodesAction.setSummary(R.string.feed_new_episodes_action_summary_autodownload);
              return;
          }
          newEpisodesAction.setEnabled(true);
          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;
      }
  }