content: package com.robobunny.preferences;
  
  import android.content.Context;
  import android.content.res.TypedArray;
  import android.preference.Preference;
  import android.util.AttributeSet;
  import android.view.View;
  import android.view.ViewGroup;
  import android.view.ViewParent;
  import android.widget.LinearLayout;
  import android.widget.SeekBar;
  import android.widget.SeekBar.OnSeekBarChangeListener;
  import android.widget.TextView;
  
  import androidx.annotation.NonNull;
  
  import com.gelakinetic.mtgfam.R;
  
  public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {
  
      private static final String ANDROIDNS = "https://schemas.android.com/apk/res/android";
      private static final String APPLICATIONNS = "https://robobunny.com";
      private static final int DEFAULT_VALUE = 50;
      private int mMaxValue = 100;
      private int mMinValue = 0;
      private int mInterval = 1;
      private int mCurrentValue;
      private String mUnitsLeft = "";
      private String mUnitsRight = "";
      private SeekBar mSeekBar;
  
      private TextView mStatusText;
  
      public SeekBarPreference(Context context, AttributeSet attrs) {
          super(context, attrs);
          initPreference(context, attrs);
      }
  
      public SeekBarPreference(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
          initPreference(context, attrs);
      }
  
      private void initPreference(Context context, AttributeSet attrs) {
          setValuesFromXml(attrs);
          mSeekBar = new SeekBar(context, attrs);
          mSeekBar.setMax(mMaxValue - mMinValue);
          mSeekBar.setOnSeekBarChangeListener(this);
  
          setWidgetLayoutResource(R.layout.seek_bar_preference);
      }
  
      private void setValuesFromXml(AttributeSet attrs) {
          mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", 100);
          mMinValue = attrs.getAttributeIntValue(APPLICATIONNS, "min", 0);
  
          mUnitsLeft = getAttributeStringValue(attrs, "unitsLeft", "");
          String units = getAttributeStringValue(attrs, "units", "");
          mUnitsRight = getAttributeStringValue(attrs, "unitsRight", units);
  
          try {
              String newInterval = attrs.getAttributeValue(APPLICATIONNS, "interval");
              if (newInterval != null)
                  mInterval = Integer.parseInt(newInterval);
          } catch (Exception e) {
              /* Eat it */
          }
  
      }
  
      private String getAttributeStringValue(AttributeSet attrs, String name, String defaultValue) {
          String value = attrs.getAttributeValue(SeekBarPreference.APPLICATIONNS, name);
          if (value == null)
              value = defaultValue;
  
          return value;
      }
  
      @Override
      protected View onCreateView(ViewGroup parent) {
          View view = super.onCreateView(parent);
  
          // The basic preference layout puts the widget frame to the right of the title and summary,
          // so we need to change it a bit - the seekbar should be under them.
          LinearLayout layout = (LinearLayout) view;
          layout.setOrientation(LinearLayout.VERTICAL);
  
          return view;
      }
  
      @Override
      public void onBindView(@NonNull View view) {
          super.onBindView(view);
  
          try {
              // move our seekbar to the new view we've been given
              ViewParent oldContainer = mSeekBar.getParent();
              ViewGroup newContainer = view.findViewById(R.id.seekBarPrefBarContainer);
  
              if (oldContainer != newContainer) {
                  // remove the seekbar from the old view
                  if (oldContainer != null) {
                      ((ViewGroup) oldContainer).removeView(mSeekBar);
                  }
                  // remove the existing seekbar (there may not be one) and add ours
                  newContainer.removeAllViews();
                  newContainer.addView(mSeekBar, ViewGroup.LayoutParams.MATCH_PARENT,
                          ViewGroup.LayoutParams.WRAP_CONTENT);
              }
          } catch (Exception ex) {
              /* Eat it */
          }
  
          //if dependency is false from the beginning, disable the seek bar
          if (!view.isEnabled()) {
              mSeekBar.setEnabled(false);
          }
  
          updateView(view);
      }
  
      /**
       * Update a SeekBarPreference view with our current state
       *
       * @param view The SeekBar view to update (seek_bar_preference.xml)
       */
      private void updateView(View view) {
  
          try {
              mStatusText = view.findViewById(R.id.seekBarPrefValue);
  
              mStatusText.setText(String.valueOf(mCurrentValue));
              mStatusText.setMinimumWidth(30);
  
              mSeekBar.setProgress(mCurrentValue - mMinValue);
  
              TextView unitsRight = view.findViewById(R.id.seekBarPrefUnitsRight);
              unitsRight.setText(mUnitsRight);
  
              TextView unitsLeft = view.findViewById(R.id.seekBarPrefUnitsLeft);
              unitsLeft.setText(mUnitsLeft);
  
          } catch (Exception e) {
              /* Eat it */
          }
  
      }
  
      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
          int newValue = progress + mMinValue;
  
          if (newValue > mMaxValue)
              newValue = mMaxValue;
          else if (newValue < mMinValue)
              newValue = mMinValue;
          else if (mInterval != 1 && newValue % mInterval != 0)
              newValue = Math.round(((float) newValue) / mInterval) * mInterval;
  
          // change rejected, revert to the previous value
          if (!callChangeListener(newValue)) {
              seekBar.setProgress(mCurrentValue - mMinValue);
              return;
          }
  
          // change accepted, store it
          mCurrentValue = newValue;
          mStatusText.setText(String.valueOf(newValue));
          persistInt(newValue);
  
      }
  
      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
      }
  
      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
          notifyChanged();
      }
  
  
      @Override
      protected Object onGetDefaultValue(TypedArray ta, int index) {
  
          return ta.getInt(index, DEFAULT_VALUE);
  
      }
  
      @Override
      protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
  
          if (restoreValue) {
              mCurrentValue = getPersistedInt(mCurrentValue);
          } else {
              int temp = 0;
              try {
                  temp = (Integer) defaultValue;
              } catch (Exception ex) {
                  /* Eat it */
              }
  
              persistInt(temp);
              mCurrentValue = temp;
          }
  
      }
  
      /**
       * make sure that the seekbar is disabled if the preference is disabled
       */
      @Override
      public void setEnabled(boolean enabled) {
          super.setEnabled(enabled);
          mSeekBar.setEnabled(enabled);
      }
  
      @Override
      public void onDependencyChanged(Preference dependency, boolean disableDependent) {
          super.onDependencyChanged(dependency, disableDependent);
  
          //Disable movement of seek bar when dependency is false
          if (mSeekBar != null) {
              mSeekBar.setEnabled(!disableDependent);
          }
      }
  }
  