From aa850ecfc677e999231a5744b96b71903ffe33dc Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 30 May 2021 03:40:30 -0700 Subject: [PATCH] Adds a Stepper control and uses it for the steppers in the editor. --- .../monstercards/ui/components/Stepper.java | 144 +++++++++ .../EditAbilityScoresFragment.java | 80 ++--- .../ui/editmonster/EditSpeedFragment.java | 67 ++--- app/src/main/res/layout/component_stepper.xml | 46 +++ .../layout/fragment_edit_ability_scores.xml | 279 +++--------------- .../main/res/layout/fragment_edit_speed.xml | 230 +++------------ app/src/main/res/values/attrs.xml | 9 + app/src/main/res/values/strings.xml | 2 + 8 files changed, 329 insertions(+), 528 deletions(-) create mode 100644 app/src/main/java/com/majinnaibu/monstercards/ui/components/Stepper.java create mode 100644 app/src/main/res/layout/component_stepper.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/components/Stepper.java b/app/src/main/java/com/majinnaibu/monstercards/ui/components/Stepper.java new file mode 100644 index 0000000..1ae029a --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/components/Stepper.java @@ -0,0 +1,144 @@ +package com.majinnaibu.monstercards.ui.components; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.constraintlayout.widget.ConstraintLayout; + +import com.majinnaibu.monstercards.R; +import com.majinnaibu.monstercards.utils.Logger; + +import java.util.Objects; + + +public class Stepper extends ConstraintLayout { + private final ViewHolder mHolder; + private int mCurrentValue; + private int mStep; + private int mMinValue; + private int mMaxValue; + private String mLabel; + private OnValueChangeListener mOnValueChangeListener; + private OnFormatValueCallback mOnFormatValueCallback; + + public Stepper(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + + mCurrentValue = 0; + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Stepper, 0, 0); + mStep = a.getInt(R.styleable.Stepper_stepAmount, 1); + mMinValue = a.getInt(R.styleable.Stepper_minValue, Integer.MIN_VALUE); + mMaxValue = a.getInt(R.styleable.Stepper_maxValue, Integer.MAX_VALUE); + mLabel = a.getString(R.styleable.Stepper_label); + a.recycle(); + + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View root = inflater.inflate(R.layout.component_stepper, this, true); + + mHolder = new ViewHolder(root); + + setValue(mCurrentValue); + mHolder.increment.setOnClickListener(v -> setValue(mCurrentValue + mStep)); + mHolder.decrement.setOnClickListener(v -> setValue(mCurrentValue - mStep)); + + mHolder.label.setText(mLabel); + } + + public Stepper(Context context) { + this(context, null); + } + + public String getLabel() { + return mLabel; + } + + public void setLabel(String newLabel) { + if (!Objects.equals(mLabel, newLabel)) { + mLabel = newLabel; + mHolder.label.setText(mLabel); + } + } + + public int getValue() { + return mCurrentValue; + } + + public void setValue(int value) { + int oldValue = this.mCurrentValue; + int newValue = Math.min(mMaxValue, Math.max(mMinValue, value)); + Logger.logDebug(String.format("Setting stepper value value: %d, oldValue: %d, newValue: %d", value, oldValue, newValue)); + if (newValue != oldValue) { + this.mCurrentValue = newValue; + if (mOnValueChangeListener != null) { + mOnValueChangeListener.onChange(newValue, oldValue); + } + if (mOnFormatValueCallback != null) { + mHolder.text.setText(mOnFormatValueCallback.onFormatValue(this.mCurrentValue)); + } else { + mHolder.text.setText(String.valueOf(this.mCurrentValue)); + } + } + } + + public void setOnValueChangeListener(OnValueChangeListener listener) { + mOnValueChangeListener = listener; + } + + public void setOnFormatValueCallback(OnFormatValueCallback callback) { + mOnFormatValueCallback = callback; + } + + public int getStep() { + return mStep; + } + + public void setStep(int step) { + this.mStep = step; + } + + public int getMinValue() { + return mMinValue; + } + + public void setMinValue(int minValue) { + this.mMinValue = minValue; + } + + public int getMaxValue() { + return mMaxValue; + } + + public void setMaxValue(int maxValue) { + this.mMaxValue = maxValue; + } + + public interface OnValueChangeListener { + void onChange(int value, int previousValue); + } + + public interface OnFormatValueCallback { + String onFormatValue(int value); + } + + private static class ViewHolder { + final TextView text; + final TextView label; + final Button increment; + final Button decrement; + + ViewHolder(View root) { + text = root.findViewById(R.id.text); + label = root.findViewById(R.id.label); + increment = root.findViewById(R.id.increment); + decrement = root.findViewById(R.id.decrement); + } + } +} diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java index 0b36fd4..697a287 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java @@ -4,8 +4,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.TextView; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; @@ -14,11 +12,17 @@ import androidx.navigation.NavController; import androidx.navigation.Navigation; import com.majinnaibu.monstercards.R; +import com.majinnaibu.monstercards.ui.components.Stepper; public class EditAbilityScoresFragment extends Fragment { + private final String ABILITY_SCORE_FORMAT = "%d (%+d)"; private EditMonsterViewModel mViewModel; private ViewHolder mHolder; + private int getModifier(int value) { + return value / 2 - 5; + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -31,72 +35,48 @@ public class EditAbilityScoresFragment extends Fragment { mHolder = new ViewHolder(root); - mViewModel.getStrength().observe(getViewLifecycleOwner(), value -> mHolder.strength.setText(String.valueOf(value))); - mHolder.increaseStrength.setOnClickListener(v -> mViewModel.incrementStrength()); - mHolder.decreaseStrength.setOnClickListener(v -> mViewModel.decrementStrength()); + mViewModel.getStrength().observe(getViewLifecycleOwner(), value -> mHolder.strength.setValue(value)); + mHolder.strength.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setStrength(newValue)); + mHolder.strength.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); - mViewModel.getDexterity().observe(getViewLifecycleOwner(), value -> mHolder.dexterity.setText(String.valueOf(value))); - mHolder.increaseDexterity.setOnClickListener(v -> mViewModel.incrementDexterity()); - mHolder.decreaseDexterity.setOnClickListener(v -> mViewModel.decrementDexterity()); + mViewModel.getDexterity().observe(getViewLifecycleOwner(), value -> mHolder.dexterity.setValue(value)); + mHolder.dexterity.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setDexterity(newValue)); + mHolder.dexterity.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); - mViewModel.getConstitution().observe(getViewLifecycleOwner(), value -> mHolder.constitution.setText(String.valueOf(value))); - mHolder.increaseConstitution.setOnClickListener(v -> mViewModel.incrementConstitution()); - mHolder.decreaseConstitution.setOnClickListener(v -> mViewModel.decrementConstitution()); + mViewModel.getConstitution().observe(getViewLifecycleOwner(), value -> mHolder.constitution.setValue(value)); + mHolder.constitution.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setConstitution(newValue)); + mHolder.constitution.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); - mViewModel.getIntelligence().observe(getViewLifecycleOwner(), value -> mHolder.intelligence.setText(String.valueOf(value))); - mHolder.increaseIntelligence.setOnClickListener(v -> mViewModel.incrementIntelligence()); - mHolder.decreaseIntelligence.setOnClickListener(v -> mViewModel.decrementIntelligence()); + mViewModel.getIntelligence().observe(getViewLifecycleOwner(), value -> mHolder.intelligence.setValue(value)); + mHolder.intelligence.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setIntelligence(newValue)); + mHolder.intelligence.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); - mViewModel.getWisdom().observe(getViewLifecycleOwner(), value -> mHolder.wisdom.setText(String.valueOf(value))); - mHolder.increaseWisdom.setOnClickListener(v -> mViewModel.incrementWisdom()); - mHolder.decreaseWisdom.setOnClickListener(v -> mViewModel.decrementWisdom()); + mViewModel.getWisdom().observe(getViewLifecycleOwner(), value -> mHolder.wisdom.setValue(value)); + mHolder.wisdom.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setWisdom(newValue)); + mHolder.wisdom.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); - mViewModel.getCharisma().observe(getViewLifecycleOwner(), value -> mHolder.charisma.setText(String.valueOf(value))); - mHolder.increaseCharisma.setOnClickListener(v -> mViewModel.incrementCharisma()); - mHolder.decreaseCharisma.setOnClickListener(v -> mViewModel.decrementCharisma()); + mViewModel.getCharisma().observe(getViewLifecycleOwner(), value -> mHolder.charisma.setValue(value)); + mHolder.charisma.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setCharisma(newValue)); + mHolder.charisma.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value))); return root; } private static class ViewHolder { - TextView strength; - Button decreaseStrength; - Button increaseStrength; - TextView dexterity; - Button increaseDexterity; - Button decreaseDexterity; - TextView constitution; - Button increaseConstitution; - Button decreaseConstitution; - TextView intelligence; - Button increaseIntelligence; - Button decreaseIntelligence; - TextView wisdom; - Button increaseWisdom; - Button decreaseWisdom; - TextView charisma; - Button increaseCharisma; - Button decreaseCharisma; + final Stepper strength; + final Stepper dexterity; + final Stepper constitution; + final Stepper intelligence; + final Stepper wisdom; + final Stepper charisma; ViewHolder(View root) { strength = root.findViewById(R.id.strength); - increaseStrength = root.findViewById(R.id.strength_increment); - decreaseStrength = root.findViewById(R.id.strength_decrement); dexterity = root.findViewById(R.id.dexterity); - increaseDexterity = root.findViewById(R.id.dexterity_increment); - decreaseDexterity = root.findViewById(R.id.dexterity_decrement); constitution = root.findViewById(R.id.constitution); - increaseConstitution = root.findViewById(R.id.constitution_increment); - decreaseConstitution = root.findViewById(R.id.constitution_decrement); intelligence = root.findViewById(R.id.intelligence); - increaseIntelligence = root.findViewById(R.id.intelligence_increment); - decreaseIntelligence = root.findViewById(R.id.intelligence_decrement); wisdom = root.findViewById(R.id.wisdom); - increaseWisdom = root.findViewById(R.id.wisdom_increment); - decreaseWisdom = root.findViewById(R.id.wisdom_decrement); charisma = root.findViewById(R.id.charisma); - increaseCharisma = root.findViewById(R.id.charisma_increment); - decreaseCharisma = root.findViewById(R.id.charisma_decrement); } } } \ No newline at end of file diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java index 7ffb29f..0cf820e 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java @@ -4,9 +4,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.EditText; -import android.widget.TextView; import androidx.appcompat.widget.SwitchCompat; import androidx.fragment.app.Fragment; @@ -16,6 +14,7 @@ import androidx.navigation.NavController; import androidx.navigation.Navigation; import com.majinnaibu.monstercards.R; +import com.majinnaibu.monstercards.ui.components.Stepper; import com.majinnaibu.monstercards.utils.TextChangedListener; public class EditSpeedFragment extends Fragment { @@ -34,29 +33,25 @@ public class EditSpeedFragment extends Fragment { mHolder = new ViewHolder(root); - mViewModel.getWalkSpeed().observe(getViewLifecycleOwner(), value -> { - mHolder.baseSpeed.setText(String.format(getString(R.string.format_distance_in_feet), value)); - }); - mHolder.incrementBaseSpeed.setOnClickListener(v -> mViewModel.incrementWalkSpeed()); - mHolder.decrementBaseSpeed.setOnClickListener(v -> mViewModel.decrementWalkSpeed()); + mHolder.baseSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setWalkSpeed(newValue)); + mHolder.baseSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value)); + mViewModel.getWalkSpeed().observe(getViewLifecycleOwner(), value -> mHolder.baseSpeed.setValue(value)); - mViewModel.getBurrowSpeed().observe(getViewLifecycleOwner(), value -> { - mHolder.burrowSpeed.setText(String.format(getString(R.string.format_distance_in_feet), value)); - }); - mHolder.incrementBurrowSpeed.setOnClickListener(v -> mViewModel.incrementBurrowSpeed()); - mHolder.decrementBurrowSpeed.setOnClickListener(v -> mViewModel.decrementBurrowSpeed()); + mHolder.burrowSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setBurrowSpeed(newValue)); + mHolder.burrowSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value)); + mViewModel.getBurrowSpeed().observe(getViewLifecycleOwner(), value -> mHolder.burrowSpeed.setValue(value)); - mViewModel.getClimbSpeed().observe(getViewLifecycleOwner(), value -> mHolder.climbSpeed.setText(String.format(getString(R.string.format_distance_in_feet), value))); - mHolder.incrementClimbSpeed.setOnClickListener(v -> mViewModel.incrementClimbSpeed()); - mHolder.decrementBurrowSpeed.setOnClickListener(v -> mViewModel.decrementClimbSpeed()); + mHolder.climbSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setClimbSpeed(newValue)); + mHolder.climbSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value)); + mViewModel.getClimbSpeed().observe(getViewLifecycleOwner(), value -> mHolder.climbSpeed.setValue(value)); - mViewModel.getFlySpeed().observe(getViewLifecycleOwner(), value -> mHolder.flySpeed.setText(String.format(getString(R.string.format_distance_in_feet), value))); - mHolder.incrementFlySpeed.setOnClickListener(v -> mViewModel.incrementFlySpeed()); - mHolder.decrementBurrowSpeed.setOnClickListener(v -> mViewModel.decrementFlySpeed()); + mHolder.flySpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setFlySpeed(newValue)); + mHolder.flySpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value)); + mViewModel.getFlySpeed().observe(getViewLifecycleOwner(), value -> mHolder.flySpeed.setValue(value)); - mViewModel.getSwimSpeed().observe(getViewLifecycleOwner(), value -> mHolder.swimSpeed.setText(String.format(getString(R.string.format_distance_in_feet), value))); - mHolder.incrementSwimSpeed.setOnClickListener(v -> mViewModel.incrementSwimSpeed()); - mHolder.decrementBurrowSpeed.setOnClickListener(v -> mViewModel.decrementSwimSpeed()); + mHolder.swimSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setSwimSpeed(newValue)); + mHolder.swimSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value)); + mViewModel.getSwimSpeed().observe(getViewLifecycleOwner(), value -> mHolder.swimSpeed.setValue(value)); mViewModel.getCanHover().observe(getViewLifecycleOwner(), value -> mHolder.canHover.setChecked(value)); mHolder.canHover.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.setCanHover(isChecked)); @@ -73,41 +68,21 @@ public class EditSpeedFragment extends Fragment { private static class ViewHolder { - final TextView baseSpeed; - final Button incrementBaseSpeed; - final Button decrementBaseSpeed; - final TextView burrowSpeed; - final Button incrementBurrowSpeed; - final Button decrementBurrowSpeed; - final TextView climbSpeed; - final Button incrementClimbSpeed; - final Button decrementClimbSpeed; - final TextView flySpeed; - final Button incrementFlySpeed; - final Button decrementFlySpeed; - final TextView swimSpeed; - final Button incrementSwimSpeed; - final Button decrementSwimSpeed; + final Stepper baseSpeed; + final Stepper burrowSpeed; + final Stepper climbSpeed; + final Stepper flySpeed; + final Stepper swimSpeed; final SwitchCompat canHover; final SwitchCompat hasCustomSpeed; final EditText customSpeed; ViewHolder(View root) { baseSpeed = root.findViewById(R.id.baseSpeed); - incrementBaseSpeed = root.findViewById(R.id.baseSpeed_increment); - decrementBaseSpeed = root.findViewById(R.id.baseSpeed_decrement); burrowSpeed = root.findViewById(R.id.burrowSpeed); - incrementBurrowSpeed = root.findViewById(R.id.burrowSpeed_increment); - decrementBurrowSpeed = root.findViewById(R.id.burrowSpeed_decrement); climbSpeed = root.findViewById(R.id.climbSpeed); - incrementClimbSpeed = root.findViewById(R.id.climbSpeed_increment); - decrementClimbSpeed = root.findViewById(R.id.climbSpeed_decrement); flySpeed = root.findViewById(R.id.flySpeed); - incrementFlySpeed = root.findViewById(R.id.flySpeed_increment); - decrementFlySpeed = root.findViewById(R.id.flySpeed_decrement); swimSpeed = root.findViewById(R.id.swimSpeed); - incrementSwimSpeed = root.findViewById(R.id.swimSpeed_increment); - decrementSwimSpeed = root.findViewById(R.id.swimSpeed_decrement); canHover = root.findViewById(R.id.canHover); hasCustomSpeed = root.findViewById(R.id.hasCustomSpeed); customSpeed = root.findViewById(R.id.customSpeed); diff --git a/app/src/main/res/layout/component_stepper.xml b/app/src/main/res/layout/component_stepper.xml new file mode 100644 index 0000000..a330941 --- /dev/null +++ b/app/src/main/res/layout/component_stepper.xml @@ -0,0 +1,46 @@ + + + + + + + +