diff --git a/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java b/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java index 46d6094..1575501 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java +++ b/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java @@ -3,6 +3,7 @@ package com.majinnaibu.monstercards.models; import android.annotation.SuppressLint; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @@ -531,10 +532,9 @@ public class Monster { int dieSize = Helpers.getHitDieForSize(size); int conMod = getConstitutionModifier(); // For PC style calculations use this - //int hpTotal = (int) Math.max(1, Math.ceil(dieSize + conMod + (hitDice - 1) * ((dieSize + 1) / 2.0 + conMod))); + //return (int) Math.max(1, Math.ceil(dieSize + conMod + (hitDice - 1) * ((dieSize + 1) / 2.0 + conMod))); // For monster style calculations use this - int hpTotal = (int) Math.max(1, Math.ceil(hitDice * ((dieSize + 1) / 2.0 + conMod))); - return hpTotal; + return (int) Math.max(1, Math.ceil(hitDice * ((dieSize + 1) / 2.0 + conMod))); } } @@ -817,6 +817,235 @@ public class Monster { return actionDescriptions; } + @Override + public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof Monster)) { + return false; + } + Monster other = (Monster) obj; + if (!challengeRating.equals(other.challengeRating)) { + return false; + } + if (!understandsButDescription.equals(other.understandsButDescription)) { + return false; + } + if (!languages.equals(other.languages)) { + return false; + } + if (!damageVulnerabilities.equals(other.damageVulnerabilities)) { + return false; + } + if (!damageResistances.equals(other.damageResistances)) { + return false; + } + if (!damageImmunities.equals(other.damageImmunities)) { + return false; + } + if (!conditionImmunities.equals(other.conditionImmunities)) { + return false; + } + if (!charismaSavingThrowProficiency.equals(other.charismaSavingThrowProficiency)) { + return false; + } + if (!wisdomSavingThrowProficiency.equals(other.wisdomSavingThrowProficiency)) { + return false; + } + if (!intelligenceSavingThrowProficiency.equals(other.intelligenceSavingThrowProficiency)) { + return false; + } + if (constitutionSavingThrowProficiency.equals(other.constitutionSavingThrowProficiency)) { + return false; + } + + if (dexteritySavingThrowProficiency.equals(other.dexteritySavingThrowProficiency)) { + return false; + } + + if (strengthSavingThrowProficiency.equals(other.strengthSavingThrowProficiency)) { + return false; + } + + if (legendaryActions.equals(other.legendaryActions)) { + return false; + } + + if (customChallengeRatingDescription.equals(other.customChallengeRatingDescription)) { + return false; + } + + if (customSpeedDescription.equals(other.customSpeedDescription)) { + return false; + } + + if (customHPDescription.equals(other.customHPDescription)) { + return false; + } + + if (otherArmorDescription.equals(other.otherArmorDescription)) { + return false; + } + + if (alignment.equals(other.alignment)) { + return false; + } + + if (subtype.equals(other.subtype)) { + return false; + } + + if (abilities.equals(other.abilities)) { + return false; + } + + if (actions.equals(other.actions)) { + return false; + } + + if (armorType.equals(other.armorType)) { + return false; + } + + if (charismaSavingThrowAdvantage.equals(other.charismaSavingThrowAdvantage)) { + return false; + } + + if (constitutionSavingThrowAdvantage.equals(other.constitutionSavingThrowAdvantage)) { + return false; + } + + if (dexteritySavingThrowAdvantage.equals(other.dexteritySavingThrowAdvantage)) { + return false; + } + + if (hitDice == other.hitDice) { + return false; + } + + if (id.equals(other.id)) { + return false; + } + + if (intelligenceSavingThrowAdvantage.equals(other.intelligenceSavingThrowAdvantage)) { + return false; + } + + if (lairActions.equals(other.lairActions)) { + return false; + } + + if (name.equals(other.name)) { + return false; + } + + if (reactions.equals(other.reactions)) { + return false; + } + + if (regionalActions.equals(other.regionalActions)) { + return false; + } + + if (senses.equals(other.senses)) { + return false; + } + + if (shieldBonus == other.shieldBonus) { + return false; + } + + if (size.equals(other.size)) { + return false; + } + + if (skills.equals(other.skills)) { + return false; + } + + if (strengthSavingThrowAdvantage.equals(other.strengthSavingThrowAdvantage)) { + return false; + } + + if (strengthScore == other.strengthScore) { + return false; + } + + if (type.equals(other.type)) { + return false; + } + + if (wisdomSavingThrowAdvantage.equals(other.wisdomSavingThrowAdvantage)) { + return false; + } + + if (wisdomScore == other.wisdomScore) { + return false; + } + if (customProficiencyBonus == other.customProficiencyBonus) { + return false; + } + + if (telepathyRange == other.telepathyRange) { + return false; + } + + if (intelligenceScore == other.intelligenceScore) { + return false; + } + + if (constitutionScore == other.constitutionScore) { + return false; + } + + if (dexterityScore == other.dexterityScore) { + return false; + } + + if (hasCustomSpeed == other.hasCustomSpeed) { + return false; + } + + if (hasCustomHP == other.hasCustomHP) { + return false; + } + + if (swimSpeed == other.swimSpeed) { + return false; + } + + if (flySpeed == other.flySpeed) { + return false; + } + + if (climbSpeed == other.climbSpeed) { + return false; + } + + if (burrowSpeed == other.burrowSpeed) { + return false; + } + + if (walkSpeed == other.walkSpeed) { + return false; + } + + if (naturalArmorBonus == other.naturalArmorBonus) { + return false; + } + + if (canHover == other.canHover) { + return false; + } + + if (charismaScore == other.charismaScore) { + return false; + } + + return true; + } + public static class Helpers { public static int getAbilityModifierForScore(int score) { return (int) Math.floor((score - 10) / 2.0); diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java index c6116e5..f2a4ba3 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java @@ -1,22 +1,21 @@ package com.majinnaibu.monstercards.ui.dashboard; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.GridLayout; -import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavDirections; +import androidx.navigation.Navigation; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.majinnaibu.monstercards.R; -import com.majinnaibu.monstercards.data.enums.AbilityScore; -import com.majinnaibu.monstercards.data.enums.AdvantageType; -import com.majinnaibu.monstercards.data.enums.ChallengeRating; -import com.majinnaibu.monstercards.data.enums.ProficiencyType; import com.majinnaibu.monstercards.models.Monster; -import com.majinnaibu.monstercards.models.Trait; import com.majinnaibu.monstercards.ui.shared.MCFragment; import com.majinnaibu.monstercards.utils.Logger; @@ -27,8 +26,9 @@ import io.reactivex.rxjava3.schedulers.Schedulers; public class DashboardFragment extends MCFragment { private static final String MODIFIER_FORMAT = "%+d"; - private ViewHolder mHolder; private DashboardViewModel mViewModel; + private ViewHolder mHolder; + private DashboardRecyclerViewAdapter mAdapter; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -36,12 +36,7 @@ public class DashboardFragment extends MCFragment { View root = inflater.inflate(R.layout.fragment_dashboard, container, false); mHolder = new ViewHolder(root); - mViewModel.getMonsters().observe(getViewLifecycleOwner(), monsters -> { - setupMonsterCards(mHolder.monsterCards, R.layout.card_monster, monsters); - setupMonsterCards(mHolder.monsterShortCards, R.layout.card_monster_short, monsters); - setupMonsterCards(mHolder.monsterTiles, R.layout.tile_monster, monsters); - setupMonsterCards(mHolder.monsterShortTiles, R.layout.tile_monster_short, monsters); - }); + setupRecyclerView(mHolder.list); getMonsterRepository() .getMonsters() @@ -54,362 +49,38 @@ public class DashboardFragment extends MCFragment { return root; } - private void setupMonsterCards(GridLayout parent, int layout, List monsters) { - LayoutInflater inflater = LayoutInflater.from(requireContext()); - parent.removeAllViews(); - for (Monster monster : monsters) { + private void setupRecyclerView(@NonNull RecyclerView recyclerView) { + int columnCount = Math.max(1, (int) Math.floor(getResources().getConfiguration().screenWidthDp / 396)); + Logger.logWTF(String.format("Setting column count to %d", columnCount)); + Context context = requireContext(); + GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount); + recyclerView.setLayoutManager(layoutManager); + + LiveData> monsterData = mViewModel.getMonsters(); + mAdapter = new DashboardRecyclerViewAdapter(monster -> { if (monster != null) { - View root = inflater.inflate(layout, parent, false); - setupCardOrTile(root, monster, layout); - GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams(root.getLayoutParams()); - ViewGroup.LayoutParams lp2 = root.getLayoutParams(); - layoutParams.width = 0; - layoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT; - layoutParams.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 01.0f); - root.setLayoutParams(layoutParams); - parent.addView(root); + navigateToMonsterDetail(monster); + } else { + Logger.logError("Can't navigate to MonsterDetailFragment with a null monster"); } + }); + if (monsterData != null) { + monsterData.observe(getViewLifecycleOwner(), monsters -> mAdapter.submitList(monsters)); } + recyclerView.setAdapter(mAdapter); } - private void setupCardOrTile(View root, Monster monster, int layout) { - if (layout == R.layout.card_monster || layout == R.layout.card_monster_short) { - MonsterCardViewHolder holder = new MonsterCardViewHolder(root); - int numActions = monster.actions.size(); - Trait action1 = numActions > 0 ? monster.actions.get(0) : null; - Trait action2 = numActions > 1 ? monster.actions.get(1) : null; - Trait action3 = numActions > 2 ? monster.actions.get(2) : null; - setupAction(holder.action1, action1); - setupAction(holder.action2, action2); - setupAction(holder.action3, action3); - int acValue = monster.getArmorClassValue(); - holder.armorClass.value.setText(acValue <= 0 ? "*" : String.format("%d", acValue)); - holder.challengeRating.setText(String.format("CR %s", getChallengeRatingAbbreviation(monster.challengeRating))); - setupAttribute(holder.strength, monster, AbilityScore.STRENGTH); - setupAttribute(holder.dexterity, monster, AbilityScore.DEXTERITY); - setupAttribute(holder.constitution, monster, AbilityScore.CONSTITUTION); - setupAttribute(holder.intelligence, monster, AbilityScore.INTELLIGENCE); - setupAttribute(holder.wisdom, monster, AbilityScore.WISDOM); - setupAttribute(holder.charisma, monster, AbilityScore.CHARISMA); - int hpValue = monster.getHitPointsValue(); - holder.hitPoints.value.setText(hpValue <= 0 ? "*" : String.format("%d", hpValue)); - holder.meta.setText(monster.getMeta()); - holder.name.setText(monster.name); - } else { - MonsterTileViewHolder holder = new MonsterTileViewHolder(root); - holder.name.setText(monster.name); - holder.meta.setText(monster.getMeta()); - int acValue = monster.getArmorClassValue(); - holder.armorClass.value.setText(acValue <= 0 ? "*" : String.format("%d", acValue)); - holder.challengeRating.value.setText(getChallengeRatingAbbreviation(monster.challengeRating)); - int hpValue = monster.getHitPointsValue(); - holder.hitPoints.value.setText(hpValue <= 0 ? "*" : String.format("%d", hpValue)); - holder.initiative.value.setText(String.format(MODIFIER_FORMAT, monster.getDexterityModifier())); - setupAction(holder.action, monster.actions.size() > 0 ? monster.actions.get(0) : null); - } - } - - private void setupAttribute(AttributeViewHolder holder, Monster monster, AbilityScore abilityScore) { - holder.name.setText(getAbilityScoreAbbreviation(abilityScore)); - holder.modifier.setText(String.format(MODIFIER_FORMAT, monster.getAbilityModifier(abilityScore))); - holder.proficiency.setText(getProficiencyAbbreviation(monster.getSavingThrowProficiencyType(abilityScore))); - holder.advantage.setText(getAdvantageAbbreviation(monster.getSavingThrowAdvantageType(abilityScore))); - } - - private String getAbilityScoreAbbreviation(AbilityScore abilityScore) { - switch (abilityScore) { - case STRENGTH: - return "S"; - case DEXTERITY: - return "D"; - case CONSTITUTION: - return "C"; - case INTELLIGENCE: - return "I"; - case WISDOM: - return "W"; - case CHARISMA: - return "Ch"; - default: - Logger.logUnimplementedFeature(String.format("Get an abbreviation for AbilityScore value %s", abilityScore)); - return ""; - } - } - - private String getChallengeRatingAbbreviation(ChallengeRating challengeRating) { - Logger.logUnimplementedMethod(); - switch (challengeRating) { - case CUSTOM: - return "*"; - case ZERO: - return "0"; - case ONE_EIGHTH: - return "1/8"; - case ONE_QUARTER: - return "1/4"; - case ONE_HALF: - return "1/2"; - case ONE: - return "1"; - case TWO: - return "2"; - case THREE: - return "3"; - case FOUR: - return "4"; - case FIVE: - return "5"; - case SIX: - return "6"; - case SEVEN: - return "7"; - case EIGHT: - return "8"; - case NINE: - return "9"; - case TEN: - return "10"; - case ELEVEN: - return "11"; - case TWELVE: - return "12"; - case THIRTEEN: - return "13"; - case FOURTEEN: - return "14"; - case FIFTEEN: - return "15"; - case SIXTEEN: - return "16"; - case SEVENTEEN: - return "17"; - case EIGHTEEN: - return "18"; - case NINETEEN: - return "19"; - case TWENTY: - return "20"; - case TWENTY_ONE: - return "21"; - case TWENTY_TWO: - return "22"; - case TWENTY_THREE: - return "23"; - case TWENTY_FOUR: - return "24"; - case TWENTY_FIVE: - return "25"; - case TWENTY_SIX: - return "26"; - case TWENTY_SEVEN: - return "27"; - case TWENTY_EIGHT: - return "28"; - case TWENTY_NINE: - return "29"; - case THIRTY: - return "30"; - default: - Logger.logUnimplementedFeature(String.format("Get an abbreviation for ChallengeRating value %s", challengeRating)); - return ""; - } - } - - private String getProficiencyAbbreviation(ProficiencyType proficiency) { - switch (proficiency) { - case NONE: - return ""; - case EXPERTISE: - return "E"; - case PROFICIENT: - return "P"; - default: - Logger.logUnimplementedFeature(String.format("Get an abbreviation for ProficiencyType value %s", proficiency)); - return ""; - } - } - - private String getAdvantageAbbreviation(AdvantageType advantage) { - switch (advantage) { - case NONE: - return ""; - case ADVANTAGE: - return "A"; - case DISADVANTAGE: - return "D"; - default: - Logger.logUnimplementedFeature(String.format("Get an abbreviation for AdvantageType value %s", advantage)); - return ""; - } - } - - private void setupAction(ActionViewHolder holder, Trait action) { - if (action == null) { - if (holder.root != null) { - holder.root.setVisibility(View.INVISIBLE); - } - } else { - if (holder.name != null) { - holder.name.setText(action.name); - } - if (holder.description != null) { - holder.description.setText(action.description); - } - } + private void navigateToMonsterDetail(Monster monster) { + NavDirections action = DashboardFragmentDirections.actionNavigationDashboardToNavigationMonster(monster.id.toString()); + Navigation.findNavController(requireView()).navigate(action); } private static class ViewHolder { - final GridLayout monsterCards; - final GridLayout monsterShortCards; - final GridLayout monsterTiles; - final GridLayout monsterShortTiles; + final RecyclerView list; ViewHolder(View root) { - monsterCards = root.findViewById(R.id.monsterCards); - monsterShortCards = root.findViewById(R.id.monsterShortCards); - monsterTiles = root.findViewById(R.id.monsterTiles); - monsterShortTiles = root.findViewById(R.id.monsterShortTiles); + list = root.findViewById(R.id.list); } } - private static class MonsterCardViewHolder { - final TextView name; - final TextView meta; - final TextView challengeRating; - final AttributeViewHolder strength; - final AttributeViewHolder dexterity; - final AttributeViewHolder constitution; - final AttributeViewHolder intelligence; - final AttributeViewHolder wisdom; - final AttributeViewHolder charisma; - final ArmorClassViewHolder armorClass; - final HitPointsViewHolder hitPoints; - final ActionViewHolder action1; - final ActionViewHolder action2; - final ActionViewHolder action3; - - MonsterCardViewHolder(View root) { - name = root.findViewById(R.id.name); - meta = root.findViewById(R.id.meta); - challengeRating = root.findViewById(R.id.challengeRating); - strength = new AttributeViewHolder(root.findViewById(R.id.strength)); - dexterity = new AttributeViewHolder(root.findViewById(R.id.dexterity)); - constitution = new AttributeViewHolder(root.findViewById(R.id.constitution)); - intelligence = new AttributeViewHolder(root.findViewById(R.id.intelligence)); - wisdom = new AttributeViewHolder(root.findViewById(R.id.wisdom)); - charisma = new AttributeViewHolder(root.findViewById(R.id.charisma)); - armorClass = new ArmorClassViewHolder(root.findViewById(R.id.armorClass)); - hitPoints = new HitPointsViewHolder(root.findViewById(R.id.hitPoints)); - action1 = new ActionViewHolder(root.findViewById(R.id.action1)); - action2 = new ActionViewHolder(root.findViewById(R.id.action2)); - action3 = new ActionViewHolder(root.findViewById(R.id.action3)); - } - } - - private static class MonsterTileViewHolder { - final TextView name; - final TextView meta; - final ArmorClassViewHolder armorClass; - final HitPointsViewHolder hitPoints; - final InitiativeViewHolder initiative; - final ChallengeRatingViewHolder challengeRating; - final ActionViewHolder action; - - MonsterTileViewHolder(View root) { - name = root.findViewById(R.id.name); - meta = root.findViewById(R.id.meta); - armorClass = new ArmorClassViewHolder(root.findViewById(R.id.armorClass)); - hitPoints = new HitPointsViewHolder(root.findViewById(R.id.hitPoints)); - initiative = new InitiativeViewHolder(root.findViewById(R.id.initiative)); - challengeRating = new ChallengeRatingViewHolder(root.findViewById(R.id.challengeRating)); - action = new ActionViewHolder(root.findViewById(R.id.action)); - } - } - - private static class ArmorClassViewHolder { - final TextView value; - - ArmorClassViewHolder(View root) { - if (root == null) { - value = null; - } else { - value = root.findViewById(R.id.value); - } - - } - } - - private static class HitPointsViewHolder { - final TextView value; - - HitPointsViewHolder(View root) { - if (root == null) { - value = null; - } else { - value = root.findViewById(R.id.value); - } - } - } - - private static class InitiativeViewHolder { - final TextView value; - - InitiativeViewHolder(View root) { - if (root == null) { - value = null; - } else { - value = root.findViewById(R.id.value); - } - } - } - - private static class ChallengeRatingViewHolder { - final TextView value; - - ChallengeRatingViewHolder(View root) { - if (root == null) { - value = null; - } else { - value = root.findViewById(R.id.value); - } - } - } - - private static class AttributeViewHolder { - final TextView name; - final TextView advantage; - final TextView proficiency; - final TextView modifier; - - AttributeViewHolder(View root) { - if (root == null) { - name = null; - advantage = null; - proficiency = null; - modifier = null; - } else { - name = root.findViewById(R.id.name); - advantage = root.findViewById(R.id.advantage); - proficiency = root.findViewById(R.id.proficiency); - modifier = root.findViewById(R.id.modifier); - } - } - } - - private static class ActionViewHolder { - final TextView name; - final TextView description; - final View root; - - ActionViewHolder(View root) { - this.root = root; - if (root == null) { - name = null; - description = null; - } else { - name = root.findViewById(R.id.name); - description = root.findViewById(R.id.description); - } - } - } } diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardRecyclerViewAdapter.java b/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardRecyclerViewAdapter.java new file mode 100644 index 0000000..6052a66 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardRecyclerViewAdapter.java @@ -0,0 +1,348 @@ +package com.majinnaibu.monstercards.ui.dashboard; + +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ListAdapter; +import androidx.recyclerview.widget.RecyclerView; + +import com.majinnaibu.monstercards.data.enums.AbilityScore; +import com.majinnaibu.monstercards.data.enums.AdvantageType; +import com.majinnaibu.monstercards.data.enums.ChallengeRating; +import com.majinnaibu.monstercards.data.enums.ProficiencyType; +import com.majinnaibu.monstercards.databinding.CardMonsterBinding; +import com.majinnaibu.monstercards.helpers.CommonMarkHelper; +import com.majinnaibu.monstercards.models.Monster; +import com.majinnaibu.monstercards.models.Trait; +import com.majinnaibu.monstercards.utils.Logger; + +import org.jetbrains.annotations.NotNull; + +public class DashboardRecyclerViewAdapter extends ListAdapter { + private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull @NotNull Monster oldItem, @NonNull @NotNull Monster newItem) { + return oldItem.id.equals(newItem.id); + } + + @Override + public boolean areContentsTheSame(@NonNull @NotNull Monster oldItem, @NonNull @NotNull Monster newItem) { + return oldItem.equals(newItem); + } + }; + private final ItemCallback mOnClick; + + protected DashboardRecyclerViewAdapter(ItemCallback onClick) { + super(DIFF_CALLBACK); + mOnClick = onClick; + } + + @NonNull + @NotNull + @Override + public ViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) { + return new ViewHolder(CardMonsterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull @NotNull ViewHolder holder, int position) { + Logger.logUnimplementedMethod(); + Monster monster = getItem(position); + holder.monster = monster; + holder.name.setText(monster.name); + holder.meta.setText(monster.getMeta()); + holder.strengthAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.strengthSavingThrowAdvantage)); + holder.strengthModifier.setText(Helpers.getModifierString(monster.getStrengthModifier())); + holder.strengthName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.STRENGTH)); + holder.strengthProficiency.setText(Helpers.getProficiencyAbbreviation(monster.strengthSavingThrowProficiency)); + + holder.dexterityAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.dexteritySavingThrowAdvantage)); + holder.dexterityModifier.setText(Helpers.getModifierString(monster.getDexterityModifier())); + holder.dexterityName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.DEXTERITY)); + holder.dexterityProficiency.setText(Helpers.getProficiencyAbbreviation(monster.dexteritySavingThrowProficiency)); + + holder.constitutionAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.constitutionSavingThrowAdvantage)); + holder.constitutionModifier.setText(Helpers.getModifierString(monster.getConstitutionModifier())); + holder.constitutionName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.CONSTITUTION)); + holder.constitutionProficiency.setText(Helpers.getProficiencyAbbreviation(monster.constitutionSavingThrowProficiency)); + + holder.intelligenceAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.intelligenceSavingThrowAdvantage)); + holder.intelligenceModifier.setText(Helpers.getModifierString(monster.getIntelligenceModifier())); + holder.intelligenceName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.INTELLIGENCE)); + holder.intelligenceProficiency.setText(Helpers.getProficiencyAbbreviation(monster.intelligenceSavingThrowProficiency)); + + holder.wisdomAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.wisdomSavingThrowAdvantage)); + holder.wisdomModifier.setText(Helpers.getModifierString(monster.getWisdomModifier())); + holder.wisdomName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.WISDOM)); + holder.wisdomProficiency.setText(Helpers.getProficiencyAbbreviation(monster.wisdomSavingThrowProficiency)); + + holder.charismaAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.charismaSavingThrowAdvantage)); + holder.charismaModifier.setText(Helpers.getModifierString(monster.getCharismaModifier())); + holder.charismaName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.CHARISMA)); + holder.charismaProficiency.setText(Helpers.getProficiencyAbbreviation(monster.charismaSavingThrowProficiency)); + + holder.armorClass.setText(String.valueOf(monster.getArmorClassValue())); + holder.hitPoints.setText(String.valueOf(monster.getHitPointsValue())); + holder.challengeRating.setText("CR " + Helpers.getChallengeRatingAbbreviation(monster.challengeRating)); + + int numActions = monster.actions.size(); + if (numActions > 0) { + holder.action1Group.setVisibility(View.VISIBLE); + Trait action = monster.actions.get(0); + holder.action1Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description))); + holder.action1Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name))); + } else { + holder.action1Group.setVisibility(View.GONE); + } + + if (numActions > 1) { + holder.action2Group.setVisibility(View.VISIBLE); + Trait action = monster.actions.get(1); + holder.action2Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description))); + holder.action2Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name))); + } else { + holder.action2Group.setVisibility(View.GONE); + } + + if (numActions > 2) { + holder.action3Group.setVisibility(View.VISIBLE); + Trait action = monster.actions.get(2); + holder.action3Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description))); + holder.action3Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name))); + } else { + holder.action3Group.setVisibility(View.GONE); + } + + holder.itemView.setOnClickListener(v -> { + if (mOnClick != null) { + mOnClick.onItemCallback(holder.monster); + } + }); + } + + public interface ItemCallback { + void onItemCallback(Monster monster); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + public final TextView name; + public final TextView meta; + public final View action1Group; + public final TextView action1Name; + public final TextView action1Description; + public final View action2Group; + public final TextView action2Name; + public final TextView action2Description; + public final View action3Group; + public final TextView action3Name; + public final TextView action3Description; + public final TextView strengthName; + public final TextView strengthModifier; + public final TextView strengthProficiency; + public final TextView strengthAdvantage; + public final TextView dexterityName; + public final TextView dexterityModifier; + public final TextView dexterityProficiency; + public final TextView dexterityAdvantage; + public final TextView constitutionName; + public final TextView constitutionModifier; + public final TextView constitutionProficiency; + public final TextView constitutionAdvantage; + public final TextView intelligenceName; + public final TextView intelligenceModifier; + public final TextView intelligenceProficiency; + public final TextView intelligenceAdvantage; + public final TextView wisdomName; + public final TextView wisdomModifier; + public final TextView wisdomProficiency; + public final TextView wisdomAdvantage; + public final TextView charismaName; + public final TextView charismaModifier; + public final TextView charismaProficiency; + public final TextView charismaAdvantage; + public final TextView armorClass; + public final TextView hitPoints; + public final TextView challengeRating; + public Monster monster; + + public ViewHolder(CardMonsterBinding binding) { + super(binding.getRoot()); + name = binding.name; + meta = binding.meta; + action1Group = binding.action1.getRoot(); + action1Name = binding.action1.name; + action1Description = binding.action1.description; + action2Group = binding.action2.getRoot(); + action2Name = binding.action2.name; + action2Description = binding.action2.description; + action3Group = binding.action3.getRoot(); + action3Name = binding.action3.name; + action3Description = binding.action3.description; + strengthName = binding.strength.name; + strengthModifier = binding.strength.modifier; + strengthProficiency = binding.strength.proficiency; + strengthAdvantage = binding.strength.advantage; + dexterityName = binding.dexterity.name; + dexterityModifier = binding.dexterity.modifier; + dexterityProficiency = binding.dexterity.proficiency; + dexterityAdvantage = binding.dexterity.advantage; + constitutionName = binding.constitution.name; + constitutionModifier = binding.constitution.modifier; + constitutionProficiency = binding.constitution.proficiency; + constitutionAdvantage = binding.constitution.advantage; + intelligenceName = binding.intelligence.name; + intelligenceModifier = binding.intelligence.modifier; + intelligenceProficiency = binding.intelligence.proficiency; + intelligenceAdvantage = binding.intelligence.advantage; + wisdomName = binding.wisdom.name; + wisdomModifier = binding.wisdom.modifier; + wisdomProficiency = binding.wisdom.proficiency; + wisdomAdvantage = binding.wisdom.advantage; + charismaName = binding.charisma.name; + charismaModifier = binding.charisma.modifier; + charismaProficiency = binding.charisma.proficiency; + charismaAdvantage = binding.charisma.advantage; + armorClass = binding.armorClass.value; + hitPoints = binding.hitPoints.value; + challengeRating = binding.challengeRating; + } + } + + public static class Helpers { + public static String getModifierString(int value) { + return String.format("%+d", value); + } + + public static String getAbilityScoreAbbreviation(AbilityScore abilityScore) { + switch (abilityScore) { + case STRENGTH: + return "S"; + case DEXTERITY: + return "D"; + case CONSTITUTION: + return "C"; + case INTELLIGENCE: + return "I"; + case WISDOM: + return "W"; + case CHARISMA: + return "Ch"; + default: + Logger.logUnimplementedFeature(String.format("Get an abbreviation for AbilityScore value %s", abilityScore)); + return ""; + } + } + + public static String getChallengeRatingAbbreviation(ChallengeRating challengeRating) { + Logger.logUnimplementedMethod(); + switch (challengeRating) { + case CUSTOM: + return "*"; + case ZERO: + return "0"; + case ONE_EIGHTH: + return "1/8"; + case ONE_QUARTER: + return "1/4"; + case ONE_HALF: + return "1/2"; + case ONE: + return "1"; + case TWO: + return "2"; + case THREE: + return "3"; + case FOUR: + return "4"; + case FIVE: + return "5"; + case SIX: + return "6"; + case SEVEN: + return "7"; + case EIGHT: + return "8"; + case NINE: + return "9"; + case TEN: + return "10"; + case ELEVEN: + return "11"; + case TWELVE: + return "12"; + case THIRTEEN: + return "13"; + case FOURTEEN: + return "14"; + case FIFTEEN: + return "15"; + case SIXTEEN: + return "16"; + case SEVENTEEN: + return "17"; + case EIGHTEEN: + return "18"; + case NINETEEN: + return "19"; + case TWENTY: + return "20"; + case TWENTY_ONE: + return "21"; + case TWENTY_TWO: + return "22"; + case TWENTY_THREE: + return "23"; + case TWENTY_FOUR: + return "24"; + case TWENTY_FIVE: + return "25"; + case TWENTY_SIX: + return "26"; + case TWENTY_SEVEN: + return "27"; + case TWENTY_EIGHT: + return "28"; + case TWENTY_NINE: + return "29"; + case THIRTY: + return "30"; + default: + Logger.logUnimplementedFeature(String.format("Get an abbreviation for ChallengeRating value %s", challengeRating)); + return ""; + } + } + + public static String getProficiencyAbbreviation(ProficiencyType proficiency) { + switch (proficiency) { + case NONE: + return ""; + case EXPERTISE: + return "E"; + case PROFICIENT: + return "P"; + default: + Logger.logUnimplementedFeature(String.format("Get an abbreviation for ProficiencyType value %s", proficiency)); + return ""; + } + } + + public static String getAdvantageAbbreviation(AdvantageType advantage) { + switch (advantage) { + case NONE: + return ""; + case ADVANTAGE: + return "A"; + case DISADVANTAGE: + return "D"; + default: + Logger.logUnimplementedFeature(String.format("Get an abbreviation for AdvantageType value %s", advantage)); + return ""; + } + } + } +} diff --git a/app/src/main/res/layout/card_monster.xml b/app/src/main/res/layout/card_monster.xml index b9503f8..ff6ee59 100644 --- a/app/src/main/res/layout/card_monster.xml +++ b/app/src/main/res/layout/card_monster.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_margin="@dimen/text_margin" android:background="@drawable/rectangle_background"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="match_parent" + android:divider="?android:attr/dividerVertical" + android:dividerPadding="@dimen/text_margin" + app:layoutManager="LinearLayoutManager" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:listitem="@layout/card_monster" /> + diff --git a/app/src/main/res/layout/fragment_dashboard_list_item.xml b/app/src/main/res/layout/fragment_dashboard_list_item.xml new file mode 100644 index 0000000..e89b69a --- /dev/null +++ b/app/src/main/res/layout/fragment_dashboard_list_item.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +