From c9a7e028ae2ae7ea500bc4d765a0d3466a2a650b Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 2 May 2021 01:30:39 -0700 Subject: [PATCH] Renames MonsterFragment to MonsterDetailFragment to better explain its use. --- .../ui/library/LibraryFragment.java | 3 - .../ui/monster/MonsterDetailFragment.java | 513 +++++++++++------- .../ui/monster/MonsterDetailViewModel.java | 176 +++--- .../ui/monster/MonsterFragment.java | 306 ----------- .../ui/monster/MonsterViewModel.java | 178 ------ .../src/main/res/layout/fragment_monster.xml | 2 +- .../main/res/navigation/mobile_navigation.xml | 10 +- 7 files changed, 385 insertions(+), 803 deletions(-) delete mode 100644 Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java delete mode 100644 Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/library/LibraryFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/library/LibraryFragment.java index 3cf8fd5..18cf407 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/library/LibraryFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/library/LibraryFragment.java @@ -35,9 +35,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.schedulers.Schedulers; public class LibraryFragment extends MCFragment { - // TODO: TOM: rename MonsterFragment MonsterDetailFragment - - private LibraryViewModel libraryViewModel; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java index f910dfa..d5cc0fa 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java @@ -8,52 +8,159 @@ import android.text.Spanned; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; -import androidx.navigation.NavDirections; -import androidx.navigation.Navigation; import com.majinnaibu.monstercards.R; -import com.majinnaibu.monstercards.data.MonsterRepository; +import com.majinnaibu.monstercards.data.enums.AbilityScore; +import com.majinnaibu.monstercards.data.enums.AdvantageType; +import com.majinnaibu.monstercards.data.enums.ArmorType; +import com.majinnaibu.monstercards.data.enums.ChallengeRating; +import com.majinnaibu.monstercards.data.enums.ProficiencyType; import com.majinnaibu.monstercards.helpers.CommonMarkHelper; import com.majinnaibu.monstercards.helpers.StringHelper; +import com.majinnaibu.monstercards.models.Language; import com.majinnaibu.monstercards.models.Monster; -import com.majinnaibu.monstercards.ui.shared.MCFragment; -import com.majinnaibu.monstercards.utils.Logger; - -import java.util.List; -import java.util.UUID; - -import io.reactivex.rxjava3.observers.DisposableSingleObserver; +import com.majinnaibu.monstercards.models.Skill; +import com.majinnaibu.monstercards.models.Trait; +<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java +@SuppressWarnings("FieldCanBeLocal") +public class MonsterFragment extends Fragment { +======== public class MonsterDetailFragment extends MCFragment { - private ViewHolder mHolder; +>>>>>>>> d78280b (Renames MonsterFragment to MonsterDetailFragment to better explain its use.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java - private MonsterDetailViewModel mViewModel; + private MonsterDetailViewModel monsterDetailViewModel; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { +<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java + + // TODO: remove this block make the monster ID a parameter to the view and get the monster from saved data (sqlite) + Monster monster = new Monster(); + // Name + monster.name = "Pixie"; + // Meta + monster.size = "tiny"; + monster.type = "fey"; + monster.subtype = ""; + monster.alignment = "neutral good"; + monster.armorType = ArmorType.NONE; + // Armor & Armor Class + monster.shieldBonus = 0; + monster.naturalArmorBonus = 7; + monster.otherArmorDescription = "14"; + // Hit Points + monster.hitDice = 1; + monster.hasCustomHP = false; + monster.customHPDescription = "11 (2d8 + 2)"; + monster.walkSpeed = 10; + monster.burrowSpeed = 0; + monster.climbSpeed = 0; + monster.flySpeed = 30; + monster.canHover = false; + monster.swimSpeed = 0; + monster.hasCustomSpeed = false; + monster.customSpeedDescription = "30 ft., swim 30 ft."; + // Ability Scores + monster.strengthScore = Integer.parseInt("2"); + monster.dexterityScore = Integer.parseInt("20"); + monster.constitutionScore = Integer.parseInt("8"); + monster.intelligenceScore = Integer.parseInt("10"); + monster.wisdomScore = Integer.parseInt("14"); + monster.charismaScore = Integer.parseInt("15"); +// monster.strengthScore = 10; +// monster.dexterityScore = 10; +// monster.constitutionScore = 10; +// monster.intelligenceScore = 10; +// monster.wisdomScore = 10; +// monster.charismaScore = 10; + + // Saving Throws + monster.strengthSavingThrowAdvantage = AdvantageType.NONE; + monster.strengthSavingThrowProficiency = ProficiencyType.NONE; + monster.dexteritySavingThrowAdvantage = AdvantageType.ADVANTAGE; + monster.dexteritySavingThrowProficiency = ProficiencyType.PROFICIENT; + monster.constitutionSavingThrowAdvantage = AdvantageType.DISADVANTAGE; + monster.constitutionSavingThrowProficiency = ProficiencyType.EXPERTISE; + monster.intelligenceSavingThrowAdvantage = AdvantageType.NONE; + monster.intelligenceSavingThrowProficiency = ProficiencyType.EXPERTISE; + monster.wisdomSavingThrowAdvantage = AdvantageType.ADVANTAGE; + monster.wisdomSavingThrowProficiency = ProficiencyType.PROFICIENT; + monster.charismaSavingThrowAdvantage = AdvantageType.DISADVANTAGE; + monster.charismaSavingThrowProficiency = ProficiencyType.NONE; + //Skills + monster.skills.add(new Skill("perception", AbilityScore.WISDOM)); + monster.skills.add(new Skill("stealth", AbilityScore.DEXTERITY)); + // Damage Types + monster.damageImmunities.add("force"); + monster.damageImmunities.add("lightning"); + monster.damageImmunities.add("poison"); + monster.damageResistances.add("cold"); + monster.damageResistances.add("fire"); + monster.damageResistances.add("piercing"); + monster.damageVulnerabilities.add("acid"); + monster.damageVulnerabilities.add("bludgeoning"); + monster.damageVulnerabilities.add("necrotic"); + // Condition Immunities + monster.conditionImmunities.add("blinded"); + // Senses + monster.blindsightRange = 10; + monster.isBlindBeyondBlindsightRange = true; + monster.darkvisionRange = 20; + monster.tremorsenseRange = 30; + monster.truesightRange = 40; + monster.telepathyRange = 20; + monster.understandsButDescription = "doesn't care"; + // Languages + monster.languages.add(new Language("English", true)); + monster.languages.add(new Language("Steve", false)); + monster.languages.add(new Language("Spanish", true)); + monster.languages.add(new Language("French", true)); + monster.languages.add(new Language("Mermataur", false)); + monster.languages.add(new Language("Goldfish", false)); + // Challenge Rating + monster.challengeRating = ChallengeRating.CUSTOM; + monster.customChallengeRatingDescription = "Infinite (0XP)"; + monster.customProficiencyBonus = 4; + // Abilities + monster.abilities.add(new Trait("Spellcasting", "The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC [WIS SAVE], [WIS ATK] to hit with spell attacks). The acolyte has following cleric spells prepared:\n\n\n> Cantrips (at will): _light, sacred flame, thaumaturgy_\n> 1st level (3 slots): _bless, cure wounds, sanctuary_")); + monster.abilities.add(new Trait("Amphibious", "The dragon can breathe air and water.")); + monster.abilities.add(new Trait("Legendary Resistance (3/Day)", "If the dragon fails a saving throw, it can choose to succeed instead.")); + // Actions + monster.actions.add(new Trait("Club", "_Melee Weapon Attack:_ [STR ATK] to hit, reach 5 ft., one target. _Hit:_ 2 (1d4) bludgeoning damage.")); + // END remove block + monsterViewModel = new ViewModelProvider(this).get(MonsterViewModel.class); + View root = inflater.inflate(R.layout.fragment_monster, container, false); + monsterViewModel.setMonster(monster); + + final TextView monsterName = root.findViewById(R.id.name); + monsterViewModel.getName().observe(getViewLifecycleOwner(), name -> monsterName.setText(name)); + + final TextView monsterMeta = root.findViewById(R.id.meta); + monsterViewModel.getMeta().observe(getViewLifecycleOwner(), metaText -> monsterMeta.setText(metaText)); +======== MonsterRepository repository = getMonsterRepository(); Bundle arguments = getArguments(); assert arguments != null; UUID monsterId = UUID.fromString(MonsterDetailFragmentArgs.fromBundle(arguments).getMonsterId()); - setHasOptionsMenu(true); - mViewModel = new ViewModelProvider(this).get(MonsterDetailViewModel.class); + + monsterDetailViewModel = new ViewModelProvider(this).get(MonsterDetailViewModel.class); + View root = inflater.inflate(R.layout.fragment_monster, container, false); + repository.getMonster(monsterId).toObservable() .firstOrError() .subscribe(new DisposableSingleObserver() { @Override public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) { - mViewModel.setMonster(monster); + monsterDetailViewModel.setMonster(monster); dispose(); } @@ -63,194 +170,192 @@ public class MonsterDetailFragment extends MCFragment { dispose(); } }); - View root = inflater.inflate(R.layout.fragment_monster, container, false); - mHolder = new ViewHolder(root); - mViewModel.getName().observe(getViewLifecycleOwner(), name -> { - mHolder.name.setText(name); - setTitle(getString(R.string.title_monsterDetails_fmt, name)); + final TextView monsterName = root.findViewById(R.id.name); + monsterDetailViewModel.getName().observe(getViewLifecycleOwner(), monsterName::setText); + + final TextView monsterMeta = root.findViewById(R.id.meta); + monsterDetailViewModel.getMeta().observe(getViewLifecycleOwner(), monsterMeta::setText); +>>>>>>>> d78280b (Renames MonsterFragment to MonsterDetailFragment to better explain its use.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java + + final TextView monsterArmorClass = root.findViewById(R.id.armor_class); + monsterDetailViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> monsterArmorClass.setText(Html.fromHtml("Armor Class " + armorText))); + + final TextView monsterHitPoints = root.findViewById(R.id.hit_points); + monsterDetailViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> monsterHitPoints.setText(Html.fromHtml("Hit Points " + hitPoints))); + + final TextView monsterSpeed = root.findViewById(R.id.speed); + monsterDetailViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> monsterSpeed.setText(Html.fromHtml("Speed " + speed))); + + final TextView monsterStrength = root.findViewById(R.id.strength); +<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java + monsterViewModel.getStrength().observe(getViewLifecycleOwner(), strength -> monsterStrength.setText(strength)); + + final TextView monsterDexterity = root.findViewById(R.id.dexterity); + monsterViewModel.getDexterity().observe(getViewLifecycleOwner(), dexterity -> monsterDexterity.setText(dexterity)); + + final TextView monsterConstitution = root.findViewById(R.id.constitution); + monsterViewModel.getConstitution().observe(getViewLifecycleOwner(), constitution -> monsterConstitution.setText(constitution)); + + final TextView monsterIntelligence = root.findViewById(R.id.intelligence); + monsterViewModel.getIntelligence().observe(getViewLifecycleOwner(), intelligence -> monsterIntelligence.setText(intelligence)); + + final TextView monsterWisdom = root.findViewById(R.id.wisdom); + monsterViewModel.getWisdom().observe(getViewLifecycleOwner(), wisdom -> monsterWisdom.setText(wisdom)); + + final TextView monsterCharisma = root.findViewById(R.id.charisma); + monsterViewModel.getCharisma().observe(getViewLifecycleOwner(), charisma -> monsterCharisma.setText(charisma)); +======== + monsterDetailViewModel.getStrength().observe(getViewLifecycleOwner(), monsterStrength::setText); + + final TextView monsterDexterity = root.findViewById(R.id.dexterity); + monsterDetailViewModel.getDexterity().observe(getViewLifecycleOwner(), monsterDexterity::setText); + + final TextView monsterConstitution = root.findViewById(R.id.constitution); + monsterDetailViewModel.getConstitution().observe(getViewLifecycleOwner(), monsterConstitution::setText); + + final TextView monsterIntelligence = root.findViewById(R.id.intelligence); + monsterDetailViewModel.getIntelligence().observe(getViewLifecycleOwner(), monsterIntelligence::setText); + + final TextView monsterWisdom = root.findViewById(R.id.wisdom); + monsterDetailViewModel.getWisdom().observe(getViewLifecycleOwner(), monsterWisdom::setText); + + final TextView monsterCharisma = root.findViewById(R.id.charisma); + monsterDetailViewModel.getCharisma().observe(getViewLifecycleOwner(), monsterCharisma::setText); +>>>>>>>> d78280b (Renames MonsterFragment to MonsterDetailFragment to better explain its use.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java + + final TextView monsterSavingThrows = root.findViewById(R.id.saving_throws); + monsterDetailViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> { + if (StringHelper.isNullOrEmpty(savingThrows)) { + monsterSavingThrows.setVisibility(View.GONE); + } else { + monsterSavingThrows.setVisibility(View.VISIBLE); + } + monsterSavingThrows.setText(Html.fromHtml("Saving Throws " + savingThrows)); + }); + + final TextView monsterSkills = root.findViewById(R.id.skills); + monsterDetailViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> { + if (StringHelper.isNullOrEmpty(skills)) { + monsterSkills.setVisibility(View.GONE); + } else { + monsterSkills.setVisibility(View.VISIBLE); + } + monsterSkills.setText(Html.fromHtml("Skills " + skills)); + }); + + final TextView monsterDamageVulnerabilities = root.findViewById(R.id.damage_vulnerabilities); + monsterDetailViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageVulnerabilities.setVisibility(View.GONE); + } else { + monsterDamageVulnerabilities.setVisibility(View.VISIBLE); + } + monsterDamageVulnerabilities.setText(Html.fromHtml("Damage Vulnerabilities " + damageType)); + }); + + final TextView monsterDamageResistances = root.findViewById(R.id.damage_resistances); + monsterDetailViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageResistances.setVisibility(View.GONE); + } else { + monsterDamageResistances.setVisibility(View.VISIBLE); + } + monsterDamageResistances.setText(Html.fromHtml("Damage Resistances " + damageType)); + }); + + final TextView monsterDamageImmunities = root.findViewById(R.id.damage_immunities); + monsterDetailViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageType -> { + if (StringHelper.isNullOrEmpty(damageType)) { + monsterDamageImmunities.setVisibility(View.GONE); + } else { + monsterDamageImmunities.setVisibility(View.VISIBLE); + } + monsterDamageImmunities.setText(Html.fromHtml("Damage Immunities " + damageType)); + }); + + final TextView monsterConditionImmunities = root.findViewById(R.id.condition_immunities); + monsterDetailViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> { + if (StringHelper.isNullOrEmpty(conditionImmunities)) { + monsterConditionImmunities.setVisibility(View.GONE); + } else { + monsterConditionImmunities.setVisibility(View.VISIBLE); + } + monsterConditionImmunities.setText(Html.fromHtml("Condition Immunities " + conditionImmunities)); + }); + + final TextView monsterSenses = root.findViewById(R.id.senses); + monsterDetailViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> { + if (StringHelper.isNullOrEmpty(senses)) { + monsterSenses.setVisibility(View.GONE); + } else { + monsterSenses.setVisibility(View.VISIBLE); + } + monsterSenses.setText(Html.fromHtml("Senses " + senses)); + }); + + final TextView monsterLanguages = root.findViewById(R.id.languages); + monsterDetailViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> { + if (StringHelper.isNullOrEmpty(languages)) { + monsterLanguages.setVisibility(View.GONE); + } else { + monsterLanguages.setVisibility(View.VISIBLE); + } + monsterLanguages.setText(Html.fromHtml("Languages " + languages)); + }); + + final TextView monsterChallenge = root.findViewById(R.id.challenge); + monsterDetailViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> monsterChallenge.setText(Html.fromHtml("Challenge " + challengeRating))); + + final LinearLayout monsterAbilities = root.findViewById(R.id.abilities); + monsterDetailViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> { + Context context = getContext(); + DisplayMetrics displayMetrics = null; + if (context != null) { + Resources resources = context.getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); + } + } + monsterAbilities.removeAllViews(); + if (abilities != null) { + for (String ability : abilities) { + TextView tvAbility = new TextView(context); + // TODO: Handle multiline block quotes specially so they stay multiline. + // TODO: Replace QuoteSpans in the result of fromHtml with something like this https://stackoverflow.com/questions/7717567/how-to-style-blockquotes-in-android-textviews to make them indent as expected + Spanned spannedText = Html.fromHtml(CommonMarkHelper.toHtml(ability)); + tvAbility.setText(spannedText); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); + tvAbility.setLayoutParams(layoutParams); + monsterAbilities.addView(tvAbility); + } + } + }); + + final LinearLayout monsterActions = root.findViewById(R.id.actions); + monsterDetailViewModel.getActions().observe(getViewLifecycleOwner(), actions -> { + Context context = getContext(); + DisplayMetrics displayMetrics = null; + if (context != null) { + Resources resources = context.getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); + } + } + monsterActions.removeAllViews(); + if (actions != null) { + for (String action : actions) { + TextView tvAction = new TextView(getContext()); + tvAction.setText(Html.fromHtml(CommonMarkHelper.toHtml(action))); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); + tvAction.setLayoutParams(layoutParams); + monsterActions.addView(tvAction); + } + } }); - mViewModel.getMeta().observe(getViewLifecycleOwner(), mHolder.meta::setText); - mViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> setupLabeledTextView(mHolder.armorClass, armorText, R.string.label_armor_class)); - mViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> setupLabeledTextView(mHolder.hitPoints, hitPoints, R.string.label_hit_points)); - mViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> setupLabeledTextView(mHolder.speed, speed, R.string.label_speed)); - mViewModel.getStrength().observe(getViewLifecycleOwner(), mHolder.strength::setText); - mViewModel.getDexterity().observe(getViewLifecycleOwner(), mHolder.dexterity::setText); - mViewModel.getConstitution().observe(getViewLifecycleOwner(), mHolder.constitution::setText); - mViewModel.getIntelligence().observe(getViewLifecycleOwner(), mHolder.intelligence::setText); - mViewModel.getWisdom().observe(getViewLifecycleOwner(), mHolder.wisdom::setText); - mViewModel.getCharisma().observe(getViewLifecycleOwner(), mHolder.charisma::setText); - mViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> setupOptionalTextView(mHolder.savingThrows, savingThrows, R.string.label_saving_throws)); - mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> setupOptionalTextView(mHolder.skills, skills, R.string.label_skills)); - mViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageVulnerabilities, damageTypes, R.string.label_damage_vulnerabilities)); - mViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageResistances, damageTypes, R.string.label_damage_resistances)); - mViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageImmunities, damageTypes, R.string.label_damage_immunities)); - mViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> setupOptionalTextView(mHolder.conditionImmunities, conditionImmunities, R.string.label_condition_immunities)); - mViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> setupOptionalTextView(mHolder.senses, senses, R.string.label_senses)); - mViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> setupOptionalTextView(mHolder.languages, languages, R.string.label_languages)); - mViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> setupLabeledTextView(mHolder.challenge, challengeRating, R.string.label_challenge_rating)); - mViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> setupTraitList(mHolder.abilities, abilities)); - mViewModel.getActions().observe(getViewLifecycleOwner(), actions -> setupTraitList(mHolder.actions, actions, mHolder.actions_label, mHolder.actions_divider)); - mViewModel.getReactions().observe(getViewLifecycleOwner(), reactions -> setupTraitList(mHolder.reactions, reactions, mHolder.reactions_label, mHolder.reactions_divider)); - mViewModel.getRegionalEffects().observe(getViewLifecycleOwner(), regionalEffects -> setupTraitList(mHolder.regionalEffects, regionalEffects, mHolder.regionalEffects_label, mHolder.regionalEffects_divider)); - mViewModel.getLairActions().observe(getViewLifecycleOwner(), lairActions -> setupTraitList(mHolder.lairActions, lairActions, mHolder.lairActions_label, mHolder.lairActions_divider)); - mViewModel.getLegendaryActions().observe(getViewLifecycleOwner(), legendaryActions -> setupTraitList(mHolder.legendaryActions, legendaryActions, mHolder.legendaryActions_label, mHolder.legendaryActions_divider)); return root; } - - private void setupLabeledTextView(@NonNull TextView view, String text, int titleId) { - String title = getString(titleId); - String fullText = String.format("%s %s", title, text); - view.setText(Html.fromHtml(fullText)); - } - - private void setupOptionalTextView(TextView root, String text, int titleId) { - String title = getString(titleId); - if (StringHelper.isNullOrEmpty(text)) { - root.setVisibility(View.GONE); - } else { - root.setVisibility(View.VISIBLE); - } - Spanned formatted; - if (StringHelper.isNullOrEmpty(title)) { - formatted = Html.fromHtml(text); - } else { - formatted = Html.fromHtml(String.format("%s %s", title, text)); - } - root.setText(formatted); - } - - private void setupTraitList(@NonNull LinearLayout root, @NonNull List traits) { - setupTraitList(root, traits, null, null); - } - - private void setupTraitList(@NonNull LinearLayout root, @NonNull List traits, View label, View divider) { - int visibility = traits.size() > 0 ? View.VISIBLE : View.GONE; - Context context = getContext(); - DisplayMetrics displayMetrics = null; - if (context != null) { - Resources resources = context.getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); - } - } - root.removeAllViews(); - for (String action : traits) { - TextView tvAction = new TextView(getContext()); - // TODO: Handle multiline block quotes specially so they stay multiline. - // TODO: Replace QuoteSpans in the result of fromHtml with something like this https://stackoverflow.com/questions/7717567/how-to-style-blockquotes-in-android-textviews to make them indent as expected - tvAction.setText(Html.fromHtml(CommonMarkHelper.toHtml(action))); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); - tvAction.setLayoutParams(layoutParams); - root.addView(tvAction); - } - root.setVisibility(visibility); - if (label != null) { - label.setVisibility(visibility); - } - if (divider != null) { - divider.setVisibility(visibility); - } - } - - @Override - public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { - inflater.inflate(R.menu.monster_detail_menu, menu); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - if (item.getItemId() == R.id.menu_action_edit_monster) { - UUID monsterId = mViewModel.getId().getValue(); - if (monsterId != null) { - NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString()); - Navigation.findNavController(requireView()).navigate(action); - } else { - Logger.logWTF("monsterId cannot be null."); - } - return true; - } - return super.onOptionsItemSelected(item); - } - - private static class ViewHolder { - final TextView name; - final TextView meta; - final TextView armorClass; - final TextView hitPoints; - final TextView speed; - final TextView strength; - final TextView dexterity; - final TextView constitution; - final TextView intelligence; - final TextView wisdom; - final TextView charisma; - final TextView savingThrows; - final TextView skills; - final TextView damageVulnerabilities; - final TextView damageResistances; - final TextView damageImmunities; - final TextView conditionImmunities; - final TextView senses; - final TextView languages; - final TextView challenge; - final LinearLayout abilities; - final LinearLayout actions; - final TextView actions_label; - final ImageView actions_divider; - final LinearLayout reactions; - final TextView reactions_label; - final ImageView reactions_divider; - final LinearLayout legendaryActions; - final TextView legendaryActions_label; - final ImageView legendaryActions_divider; - final LinearLayout lairActions; - final TextView lairActions_label; - final ImageView lairActions_divider; - final LinearLayout regionalEffects; - final TextView regionalEffects_label; - final ImageView regionalEffects_divider; - - ViewHolder(@NonNull View root) { - name = root.findViewById(R.id.name); - meta = root.findViewById(R.id.meta); - armorClass = root.findViewById(R.id.armorClass); - hitPoints = root.findViewById(R.id.hitPoints); - speed = root.findViewById(R.id.speed); - strength = root.findViewById(R.id.strength); - dexterity = root.findViewById(R.id.dexterity); - constitution = root.findViewById(R.id.constitution); - intelligence = root.findViewById(R.id.intelligence); - wisdom = root.findViewById(R.id.wisdom); - charisma = root.findViewById(R.id.charisma); - savingThrows = root.findViewById(R.id.savingThrows); - skills = root.findViewById(R.id.skills); - damageVulnerabilities = root.findViewById(R.id.damageVulnerabilities); - damageResistances = root.findViewById(R.id.damageResistances); - damageImmunities = root.findViewById(R.id.damageImmunities); - conditionImmunities = root.findViewById(R.id.conditionImmunities); - senses = root.findViewById(R.id.senses); - languages = root.findViewById(R.id.languages); - challenge = root.findViewById(R.id.challenge); - abilities = root.findViewById(R.id.abilities); - actions = root.findViewById(R.id.actions); - actions_divider = root.findViewById(R.id.actions_divider); - actions_label = root.findViewById(R.id.actions_label); - reactions = root.findViewById(R.id.reactions); - reactions_divider = root.findViewById(R.id.reactions_divider); - reactions_label = root.findViewById(R.id.reactions_label); - legendaryActions = root.findViewById(R.id.legendaryActions); - legendaryActions_divider = root.findViewById(R.id.legendaryActions_divider); - legendaryActions_label = root.findViewById(R.id.legendaryActions_label); - lairActions = root.findViewById(R.id.lairActions); - lairActions_divider = root.findViewById(R.id.lairActions_divider); - lairActions_label = root.findViewById(R.id.lairActions_label); - regionalEffects = root.findViewById(R.id.regionalEffects); - regionalEffects_divider = root.findViewById(R.id.regionalEffects_divider); - regionalEffects_label = root.findViewById(R.id.regionalEffects_label); - } - } } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailViewModel.java index 38e5d13..b2b314d 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailViewModel.java @@ -1,6 +1,5 @@ package com.majinnaibu.monstercards.ui.monster; -import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; @@ -9,180 +8,150 @@ import com.majinnaibu.monstercards.models.Monster; import java.util.ArrayList; import java.util.List; -import java.util.UUID; public class MonsterDetailViewModel extends ViewModel { - private final MutableLiveData> mAbilities; - private final MutableLiveData> mActions; - private final MutableLiveData mArmorClass; - private final MutableLiveData mChallenge; - private final MutableLiveData mCharisma; - private final MutableLiveData mConditionImmunities; - private final MutableLiveData mConstitution; - private final MutableLiveData mDamageResistances; - private final MutableLiveData mDamageImmunities; - private final MutableLiveData mDamageVulnerabilities; - private final MutableLiveData mDexterity; - private final MutableLiveData mHitPoints; - private final MutableLiveData mIntelligence; - private final MutableLiveData> mLairActions; - private final MutableLiveData mLanguages; - private final MutableLiveData> mLegendaryActions; - private final MutableLiveData mMeta; - private final MutableLiveData mName; - private final MutableLiveData> mReactions; - private final MutableLiveData> mRegionalEffects; - private final MutableLiveData mSavingThrows; - private final MutableLiveData mSenses; - private final MutableLiveData mSkills; - private final MutableLiveData mSpeed; - private final MutableLiveData mStrength; - private final MutableLiveData mWisdom; - private final MutableLiveData mMonsterId; - private Monster mMonster; - public MonsterDetailViewModel() { mMonster = null; - mAbilities = new MutableLiveData<>(new ArrayList<>()); - mActions = new MutableLiveData<>(new ArrayList<>()); - mArmorClass = new MutableLiveData<>(""); - mChallenge = new MutableLiveData<>(""); - mCharisma = new MutableLiveData<>(""); - mConditionImmunities = new MutableLiveData<>(""); - mConstitution = new MutableLiveData<>(""); - mDamageImmunities = new MutableLiveData<>(""); - mDamageResistances = new MutableLiveData<>(""); - mDamageVulnerabilities = new MutableLiveData<>(""); - mDexterity = new MutableLiveData<>(""); - mHitPoints = new MutableLiveData<>(""); - mIntelligence = new MutableLiveData<>(""); - mLairActions = new MutableLiveData<>(new ArrayList<>()); - mLanguages = new MutableLiveData<>(""); - mLegendaryActions = new MutableLiveData<>(new ArrayList<>()); - mMeta = new MutableLiveData<>(""); - mName = new MutableLiveData<>(""); - mReactions = new MutableLiveData<>(new ArrayList<>()); - mRegionalEffects = new MutableLiveData<>(new ArrayList<>()); - mSavingThrows = new MutableLiveData<>(""); - mSenses = new MutableLiveData<>(""); - mSkills = new MutableLiveData<>(""); - mSpeed = new MutableLiveData<>(""); - mStrength = new MutableLiveData<>(""); - mWisdom = new MutableLiveData<>(""); - mMonsterId = new MutableLiveData<>(UUID.fromString("00000000-0000-0000-0000-000000000000")); + mAbilities = new MutableLiveData<>(); + mAbilities.setValue(new ArrayList()); + mActions = new MutableLiveData<>(); + mActions.setValue(new ArrayList()); + mArmorClass = new MutableLiveData<>(); + mArmorClass.setValue(""); + mChallenge = new MutableLiveData<>(); + mChallenge.setValue(""); + mCharisma = new MutableLiveData<>(); + mCharisma.setValue(""); + mConditionImmunities = new MutableLiveData<>(); + mConditionImmunities.setValue(""); + mConstitution = new MutableLiveData<>(); + mConstitution.setValue(""); + mDamageImmunities = new MutableLiveData<>(); + mDamageImmunities.setValue(""); + mDamageResistances = new MutableLiveData<>(); + mDamageResistances.setValue(""); + mDamageVulnerabilities = new MutableLiveData<>(); + mDamageVulnerabilities.setValue(""); + mDexterity = new MutableLiveData<>(); + mDexterity.setValue(""); + mHitPoints = new MutableLiveData<>(); + mHitPoints.setValue(""); + mIntelligence = new MutableLiveData<>(); + mIntelligence.setValue(""); + mLanguages = new MutableLiveData<>(); + mLanguages.setValue(""); + mMeta = new MutableLiveData<>(); + mMeta.setValue(""); + mName = new MutableLiveData<>(); + mName.setValue(""); + mSavingThrows = new MutableLiveData<>(); + mSavingThrows.setValue(""); + mSenses = new MutableLiveData<>(); + mSenses.setValue(""); + mSkills = new MutableLiveData<>(); + mSkills.setValue(""); + mSpeed = new MutableLiveData<>(); + mSpeed.setValue(""); + mStrength = new MutableLiveData<>(); + mStrength.setValue(""); + mWisdom = new MutableLiveData<>(); + mWisdom.setValue(""); } + private MutableLiveData> mAbilities; public LiveData> getAbilities() { return mAbilities; } - + private MutableLiveData> mActions; public LiveData> getActions() { return mActions; } - - public LiveData> getReactions() { - return mReactions; - } - - public LiveData> getLegendaryActions() { - return mLegendaryActions; - } - - public LiveData> getLairActions() { - return mLairActions; - } - - public LiveData> getRegionalEffects() { - return mRegionalEffects; - } - + private MutableLiveData mArmorClass; public LiveData getArmorClass() { return mArmorClass; } - + private MutableLiveData mChallenge; public LiveData getChallenge() { return mChallenge; } - + private MutableLiveData mCharisma; public LiveData getCharisma() { return mCharisma; } - + private MutableLiveData mConditionImmunities; public LiveData getConditionImmunities() { return mConditionImmunities; } - + private MutableLiveData mConstitution; public LiveData getConstitution() { return mConstitution; } - + private MutableLiveData mDamageResistances; public LiveData getDamageResistances() { return mDamageResistances; } - + private MutableLiveData mDamageImmunities; public LiveData getDamageImmunities() { return mDamageImmunities; } - + private MutableLiveData mDamageVulnerabilities; public LiveData getDamageVulnerabilities() { return mDamageVulnerabilities; } - + private MutableLiveData mDexterity; public LiveData getDexterity() { return mDexterity; } - + private MutableLiveData mHitPoints; public LiveData getHitPoints() { return mHitPoints; } - + private MutableLiveData mIntelligence; public LiveData getIntelligence() { return mIntelligence; } - + private MutableLiveData mLanguages; public LiveData getLanguages() { return mLanguages; } - + private MutableLiveData mMeta; public LiveData getMeta() { return mMeta; } - + private MutableLiveData mName; public LiveData getName() { return mName; } - + private MutableLiveData mSavingThrows; public LiveData getSavingThrows() { return mSavingThrows; } - + private MutableLiveData mSenses; public LiveData getSenses() { return mSenses; } - + private MutableLiveData mSkills; public LiveData getSkills() { return mSkills; } - + private MutableLiveData mSpeed; public LiveData getSpeed() { return mSpeed; } - + private MutableLiveData mStrength; public LiveData getStrength() { return mStrength; } - + private MutableLiveData mWisdom; public LiveData getWisdom() { return mWisdom; } - public LiveData getId() { - return mMonsterId; - } - - public void setMonster(@NonNull Monster monster) { + private Monster mMonster; + public void setMonster(Monster monster) { mMonster = monster; + mAbilities.setValue(mMonster.getAbilityDescriptions()); mActions.setValue(mMonster.getActionDescriptions()); mArmorClass.setValue(mMonster.getArmorClass()); @@ -196,14 +165,9 @@ public class MonsterDetailViewModel extends ViewModel { mDexterity.setValue(monster.getDexterityDescription()); mHitPoints.setValue(mMonster.getHitPoints()); mIntelligence.setValue(monster.getIntelligenceDescription()); - mLairActions.setValue(mMonster.getLairActionDescriptions()); mLanguages.setValue(mMonster.getLanguagesDescription()); - mLegendaryActions.setValue(mMonster.getLegendaryActionDescriptions()); mMeta.setValue(mMonster.getMeta()); - mMonsterId.setValue(mMonster.id); mName.setValue(mMonster.name); - mReactions.setValue(monster.getReactionDescriptions()); - mRegionalEffects.setValue(monster.getRegionalActionDescriptions()); mSavingThrows.setValue(monster.getSavingThrowsDescription()); mSenses.setValue(monster.getSensesDescription()); mSkills.setValue(monster.getSkillsDescription()); @@ -211,4 +175,4 @@ public class MonsterDetailViewModel extends ViewModel { mStrength.setValue(monster.getStrengthDescription()); mWisdom.setValue(monster.getWisdomDescription()); } -} +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java deleted file mode 100644 index 5b4273b..0000000 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterFragment.java +++ /dev/null @@ -1,306 +0,0 @@ -package com.majinnaibu.monstercards.ui.monster; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Bundle; -import android.text.Html; -import android.text.Spanned; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; - -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.ArmorType; -import com.majinnaibu.monstercards.data.enums.ChallengeRating; -import com.majinnaibu.monstercards.data.enums.ProficiencyType; -import com.majinnaibu.monstercards.helpers.CommonMarkHelper; -import com.majinnaibu.monstercards.helpers.StringHelper; -import com.majinnaibu.monstercards.models.Language; -import com.majinnaibu.monstercards.models.Monster; -import com.majinnaibu.monstercards.models.Skill; -import com.majinnaibu.monstercards.models.Trait; - -@SuppressWarnings("FieldCanBeLocal") -public class MonsterFragment extends Fragment { - - private MonsterViewModel monsterViewModel; - - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, Bundle savedInstanceState) { - - // TODO: remove this block make the monster ID a parameter to the view and get the monster from saved data (sqlite) - Monster monster = new Monster(); - // Name - monster.name = "Pixie"; - // Meta - monster.size = "tiny"; - monster.type = "fey"; - monster.subtype = ""; - monster.alignment = "neutral good"; - monster.armorType = ArmorType.NONE; - // Armor & Armor Class - monster.shieldBonus = 0; - monster.naturalArmorBonus = 7; - monster.otherArmorDescription = "14"; - // Hit Points - monster.hitDice = 1; - monster.hasCustomHP = false; - monster.customHPDescription = "11 (2d8 + 2)"; - monster.walkSpeed = 10; - monster.burrowSpeed = 0; - monster.climbSpeed = 0; - monster.flySpeed = 30; - monster.canHover = false; - monster.swimSpeed = 0; - monster.hasCustomSpeed = false; - monster.customSpeedDescription = "30 ft., swim 30 ft."; - // Ability Scores - monster.strengthScore = Integer.parseInt("2"); - monster.dexterityScore = Integer.parseInt("20"); - monster.constitutionScore = Integer.parseInt("8"); - monster.intelligenceScore = Integer.parseInt("10"); - monster.wisdomScore = Integer.parseInt("14"); - monster.charismaScore = Integer.parseInt("15"); -// monster.strengthScore = 10; -// monster.dexterityScore = 10; -// monster.constitutionScore = 10; -// monster.intelligenceScore = 10; -// monster.wisdomScore = 10; -// monster.charismaScore = 10; - - // Saving Throws - monster.strengthSavingThrowAdvantage = AdvantageType.NONE; - monster.strengthSavingThrowProficiency = ProficiencyType.NONE; - monster.dexteritySavingThrowAdvantage = AdvantageType.ADVANTAGE; - monster.dexteritySavingThrowProficiency = ProficiencyType.PROFICIENT; - monster.constitutionSavingThrowAdvantage = AdvantageType.DISADVANTAGE; - monster.constitutionSavingThrowProficiency = ProficiencyType.EXPERTISE; - monster.intelligenceSavingThrowAdvantage = AdvantageType.NONE; - monster.intelligenceSavingThrowProficiency = ProficiencyType.EXPERTISE; - monster.wisdomSavingThrowAdvantage = AdvantageType.ADVANTAGE; - monster.wisdomSavingThrowProficiency = ProficiencyType.PROFICIENT; - monster.charismaSavingThrowAdvantage = AdvantageType.DISADVANTAGE; - monster.charismaSavingThrowProficiency = ProficiencyType.NONE; - //Skills - monster.skills.add(new Skill("perception", AbilityScore.WISDOM)); - monster.skills.add(new Skill("stealth", AbilityScore.DEXTERITY)); - // Damage Types - monster.damageImmunities.add("force"); - monster.damageImmunities.add("lightning"); - monster.damageImmunities.add("poison"); - monster.damageResistances.add("cold"); - monster.damageResistances.add("fire"); - monster.damageResistances.add("piercing"); - monster.damageVulnerabilities.add("acid"); - monster.damageVulnerabilities.add("bludgeoning"); - monster.damageVulnerabilities.add("necrotic"); - // Condition Immunities - monster.conditionImmunities.add("blinded"); - // Senses - monster.blindsightRange = 10; - monster.isBlindBeyondBlindsightRange = true; - monster.darkvisionRange = 20; - monster.tremorsenseRange = 30; - monster.truesightRange = 40; - monster.telepathyRange = 20; - monster.understandsButDescription = "doesn't care"; - // Languages - monster.languages.add(new Language("English", true)); - monster.languages.add(new Language("Steve", false)); - monster.languages.add(new Language("Spanish", true)); - monster.languages.add(new Language("French", true)); - monster.languages.add(new Language("Mermataur", false)); - monster.languages.add(new Language("Goldfish", false)); - // Challenge Rating - monster.challengeRating = ChallengeRating.CUSTOM; - monster.customChallengeRatingDescription = "Infinite (0XP)"; - monster.customProficiencyBonus = 4; - // Abilities - monster.abilities.add(new Trait("Spellcasting", "The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC [WIS SAVE], [WIS ATK] to hit with spell attacks). The acolyte has following cleric spells prepared:\n\n\n> Cantrips (at will): _light, sacred flame, thaumaturgy_\n> 1st level (3 slots): _bless, cure wounds, sanctuary_")); - monster.abilities.add(new Trait("Amphibious", "The dragon can breathe air and water.")); - monster.abilities.add(new Trait("Legendary Resistance (3/Day)", "If the dragon fails a saving throw, it can choose to succeed instead.")); - // Actions - monster.actions.add(new Trait("Club", "_Melee Weapon Attack:_ [STR ATK] to hit, reach 5 ft., one target. _Hit:_ 2 (1d4) bludgeoning damage.")); - // END remove block - monsterViewModel = new ViewModelProvider(this).get(MonsterViewModel.class); - View root = inflater.inflate(R.layout.fragment_monster, container, false); - monsterViewModel.setMonster(monster); - - final TextView monsterName = root.findViewById(R.id.name); - monsterViewModel.getName().observe(getViewLifecycleOwner(), name -> monsterName.setText(name)); - - final TextView monsterMeta = root.findViewById(R.id.meta); - monsterViewModel.getMeta().observe(getViewLifecycleOwner(), metaText -> monsterMeta.setText(metaText)); - - final TextView monsterArmorClass = root.findViewById(R.id.armor_class); - monsterViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> monsterArmorClass.setText(Html.fromHtml("Armor Class " + armorText))); - - final TextView monsterHitPoints = root.findViewById(R.id.hit_points); - monsterViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> monsterHitPoints.setText(Html.fromHtml("Hit Points " + hitPoints))); - - final TextView monsterSpeed = root.findViewById(R.id.speed); - monsterViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> monsterSpeed.setText(Html.fromHtml("Speed " + speed))); - - final TextView monsterStrength = root.findViewById(R.id.strength); - monsterViewModel.getStrength().observe(getViewLifecycleOwner(), strength -> monsterStrength.setText(strength)); - - final TextView monsterDexterity = root.findViewById(R.id.dexterity); - monsterViewModel.getDexterity().observe(getViewLifecycleOwner(), dexterity -> monsterDexterity.setText(dexterity)); - - final TextView monsterConstitution = root.findViewById(R.id.constitution); - monsterViewModel.getConstitution().observe(getViewLifecycleOwner(), constitution -> monsterConstitution.setText(constitution)); - - final TextView monsterIntelligence = root.findViewById(R.id.intelligence); - monsterViewModel.getIntelligence().observe(getViewLifecycleOwner(), intelligence -> monsterIntelligence.setText(intelligence)); - - final TextView monsterWisdom = root.findViewById(R.id.wisdom); - monsterViewModel.getWisdom().observe(getViewLifecycleOwner(), wisdom -> monsterWisdom.setText(wisdom)); - - final TextView monsterCharisma = root.findViewById(R.id.charisma); - monsterViewModel.getCharisma().observe(getViewLifecycleOwner(), charisma -> monsterCharisma.setText(charisma)); - - final TextView monsterSavingThrows = root.findViewById(R.id.saving_throws); - monsterViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> { - if (StringHelper.isNullOrEmpty(savingThrows)) { - monsterSavingThrows.setVisibility(View.GONE); - } else { - monsterSavingThrows.setVisibility(View.VISIBLE); - } - monsterSavingThrows.setText(Html.fromHtml("Saving Throws " + savingThrows)); - }); - - final TextView monsterSkills = root.findViewById(R.id.skills); - monsterViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> { - if (StringHelper.isNullOrEmpty(skills)) { - monsterSkills.setVisibility(View.GONE); - } else { - monsterSkills.setVisibility(View.VISIBLE); - } - monsterSkills.setText(Html.fromHtml("Skills " + skills)); - }); - - final TextView monsterDamageVulnerabilities = root.findViewById(R.id.damage_vulnerabilities); - monsterViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageType -> { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageVulnerabilities.setVisibility(View.GONE); - } else { - monsterDamageVulnerabilities.setVisibility(View.VISIBLE); - } - monsterDamageVulnerabilities.setText(Html.fromHtml("Damage Vulnerabilities " + damageType)); - }); - - final TextView monsterDamageResistances = root.findViewById(R.id.damage_resistances); - monsterViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageType -> { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageResistances.setVisibility(View.GONE); - } else { - monsterDamageResistances.setVisibility(View.VISIBLE); - } - monsterDamageResistances.setText(Html.fromHtml("Damage Resistances " + damageType)); - }); - - final TextView monsterDamageImmunities = root.findViewById(R.id.damage_immunities); - monsterViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageType -> { - if (StringHelper.isNullOrEmpty(damageType)) { - monsterDamageImmunities.setVisibility(View.GONE); - } else { - monsterDamageImmunities.setVisibility(View.VISIBLE); - } - monsterDamageImmunities.setText(Html.fromHtml("Damage Immunities " + damageType)); - }); - - final TextView monsterConditionImmunities = root.findViewById(R.id.condition_immunities); - monsterViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> { - if (StringHelper.isNullOrEmpty(conditionImmunities)) { - monsterConditionImmunities.setVisibility(View.GONE); - } else { - monsterConditionImmunities.setVisibility(View.VISIBLE); - } - monsterConditionImmunities.setText(Html.fromHtml("Condition Immunities " + conditionImmunities)); - }); - - final TextView monsterSenses = root.findViewById(R.id.senses); - monsterViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> { - if (StringHelper.isNullOrEmpty(senses)) { - monsterSenses.setVisibility(View.GONE); - } else { - monsterSenses.setVisibility(View.VISIBLE); - } - monsterSenses.setText(Html.fromHtml("Senses " + senses)); - }); - - final TextView monsterLanguages = root.findViewById(R.id.languages); - monsterViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> { - if (StringHelper.isNullOrEmpty(languages)) { - monsterLanguages.setVisibility(View.GONE); - } else { - monsterLanguages.setVisibility(View.VISIBLE); - } - monsterLanguages.setText(Html.fromHtml("Languages " + languages)); - }); - - final TextView monsterChallenge = root.findViewById(R.id.challenge); - monsterViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> monsterChallenge.setText(Html.fromHtml("Challenge " + challengeRating))); - - final LinearLayout monsterAbilities = root.findViewById(R.id.abilities); - monsterViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> { - Context context = getContext(); - DisplayMetrics displayMetrics = null; - if (context != null) { - Resources resources = context.getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); - } - } - monsterAbilities.removeAllViews(); - if (abilities != null) { - for (String ability : abilities) { - TextView tvAbility = new TextView(context); - // TODO: Handle multiline block quotes specially so they stay multiline. - // TODO: Replace QuoteSpans in the result of fromHtml with something like this https://stackoverflow.com/questions/7717567/how-to-style-blockquotes-in-android-textviews to make them indent as expected - Spanned spannedText = Html.fromHtml(CommonMarkHelper.toHtml(ability)); - tvAbility.setText(spannedText); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); - tvAbility.setLayoutParams(layoutParams); - monsterAbilities.addView(tvAbility); - } - } - }); - - final LinearLayout monsterActions = root.findViewById(R.id.actions); - monsterViewModel.getActions().observe(getViewLifecycleOwner(), actions -> { - Context context = getContext(); - DisplayMetrics displayMetrics = null; - if (context != null) { - Resources resources = context.getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); - } - } - monsterActions.removeAllViews(); - if (actions != null) { - for (String action : actions) { - TextView tvAction = new TextView(getContext()); - tvAction.setText(Html.fromHtml(CommonMarkHelper.toHtml(action))); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, displayMetrics); - tvAction.setLayoutParams(layoutParams); - monsterActions.addView(tvAction); - } - } - }); - - return root; - } -} diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java deleted file mode 100644 index 24b507a..0000000 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterViewModel.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.majinnaibu.monstercards.ui.monster; - -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; - -import com.majinnaibu.monstercards.models.Monster; - -import java.util.ArrayList; -import java.util.List; - -public class MonsterViewModel extends ViewModel { - - public MonsterViewModel() { - mMonster = null; - mAbilities = new MutableLiveData<>(); - mAbilities.setValue(new ArrayList()); - mActions = new MutableLiveData<>(); - mActions.setValue(new ArrayList()); - mArmorClass = new MutableLiveData<>(); - mArmorClass.setValue(""); - mChallenge = new MutableLiveData<>(); - mChallenge.setValue(""); - mCharisma = new MutableLiveData<>(); - mCharisma.setValue(""); - mConditionImmunities = new MutableLiveData<>(); - mConditionImmunities.setValue(""); - mConstitution = new MutableLiveData<>(); - mConstitution.setValue(""); - mDamageImmunities = new MutableLiveData<>(); - mDamageImmunities.setValue(""); - mDamageResistances = new MutableLiveData<>(); - mDamageResistances.setValue(""); - mDamageVulnerabilities = new MutableLiveData<>(); - mDamageVulnerabilities.setValue(""); - mDexterity = new MutableLiveData<>(); - mDexterity.setValue(""); - mHitPoints = new MutableLiveData<>(); - mHitPoints.setValue(""); - mIntelligence = new MutableLiveData<>(); - mIntelligence.setValue(""); - mLanguages = new MutableLiveData<>(); - mLanguages.setValue(""); - mMeta = new MutableLiveData<>(); - mMeta.setValue(""); - mName = new MutableLiveData<>(); - mName.setValue(""); - mSavingThrows = new MutableLiveData<>(); - mSavingThrows.setValue(""); - mSenses = new MutableLiveData<>(); - mSenses.setValue(""); - mSkills = new MutableLiveData<>(); - mSkills.setValue(""); - mSpeed = new MutableLiveData<>(); - mSpeed.setValue(""); - mStrength = new MutableLiveData<>(); - mStrength.setValue(""); - mWisdom = new MutableLiveData<>(); - mWisdom.setValue(""); - } - - private MutableLiveData> mAbilities; - public LiveData> getAbilities() { - return mAbilities; - } - private MutableLiveData> mActions; - public LiveData> getActions() { - return mActions; - } - private MutableLiveData mArmorClass; - public LiveData getArmorClass() { - return mArmorClass; - } - private MutableLiveData mChallenge; - public LiveData getChallenge() { - return mChallenge; - } - private MutableLiveData mCharisma; - public LiveData getCharisma() { - return mCharisma; - } - private MutableLiveData mConditionImmunities; - public LiveData getConditionImmunities() { - return mConditionImmunities; - } - private MutableLiveData mConstitution; - public LiveData getConstitution() { - return mConstitution; - } - private MutableLiveData mDamageResistances; - public LiveData getDamageResistances() { - return mDamageResistances; - } - private MutableLiveData mDamageImmunities; - public LiveData getDamageImmunities() { - return mDamageImmunities; - } - private MutableLiveData mDamageVulnerabilities; - public LiveData getDamageVulnerabilities() { - return mDamageVulnerabilities; - } - private MutableLiveData mDexterity; - public LiveData getDexterity() { - return mDexterity; - } - private MutableLiveData mHitPoints; - public LiveData getHitPoints() { - return mHitPoints; - } - private MutableLiveData mIntelligence; - public LiveData getIntelligence() { - return mIntelligence; - } - private MutableLiveData mLanguages; - public LiveData getLanguages() { - return mLanguages; - } - private MutableLiveData mMeta; - public LiveData getMeta() { - return mMeta; - } - private MutableLiveData mName; - public LiveData getName() { - return mName; - } - private MutableLiveData mSavingThrows; - public LiveData getSavingThrows() { - return mSavingThrows; - } - private MutableLiveData mSenses; - public LiveData getSenses() { - return mSenses; - } - private MutableLiveData mSkills; - public LiveData getSkills() { - return mSkills; - } - private MutableLiveData mSpeed; - public LiveData getSpeed() { - return mSpeed; - } - private MutableLiveData mStrength; - public LiveData getStrength() { - return mStrength; - } - private MutableLiveData mWisdom; - public LiveData getWisdom() { - return mWisdom; - } - - private Monster mMonster; - public void setMonster(Monster monster) { - mMonster = monster; - - mAbilities.setValue(mMonster.getAbilityDescriptions()); - mActions.setValue(mMonster.getActionDescriptions()); - mArmorClass.setValue(mMonster.getArmorClass()); - mChallenge.setValue(mMonster.getChallengeRatingDescription()); - mCharisma.setValue(monster.getCharismaDescription()); - mConditionImmunities.setValue(mMonster.getConditionImmunitiesDescription()); - mConstitution.setValue(monster.getConstitutionDescription()); - mDamageImmunities.setValue(mMonster.getDamageImmunitiesDescription()); - mDamageResistances.setValue(mMonster.getDamageResistancesDescription()); - mDamageVulnerabilities.setValue(mMonster.getDamageVulnerabilitiesDescription()); - mDexterity.setValue(monster.getDexterityDescription()); - mHitPoints.setValue(mMonster.getHitPoints()); - mIntelligence.setValue(monster.getIntelligenceDescription()); - mLanguages.setValue(mMonster.getLanguagesDescription()); - mMeta.setValue(mMonster.getMeta()); - mName.setValue(mMonster.name); - mSavingThrows.setValue(monster.getSavingThrowsDescription()); - mSenses.setValue(monster.getSensesDescription()); - mSkills.setValue(monster.getSkillsDescription()); - mSpeed.setValue(mMonster.getSpeedText()); - mStrength.setValue(monster.getStrengthDescription()); - mWisdom.setValue(monster.getWisdomDescription()); - } -} \ No newline at end of file diff --git a/Android/app/src/main/res/layout/fragment_monster.xml b/Android/app/src/main/res/layout/fragment_monster.xml index 7aa2002..6e2ece4 100644 --- a/Android/app/src/main/res/layout/fragment_monster.xml +++ b/Android/app/src/main/res/layout/fragment_monster.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".ui.monster.MonsterFragment"> + tools:context=".ui.monster.MonsterDetailFragment"> + tools:layout="@layout/fragment_search"> @@ -19,7 +19,7 @@ android:id="@+id/navigation_dashboard" android:name="com.majinnaibu.monstercards.ui.dashboard.DashboardFragment" android:label="@string/title_dashboard" - tools:layout="@layout/fragment_dashboard" > + tools:layout="@layout/fragment_dashboard"> @@ -29,7 +29,7 @@ android:id="@+id/navigation_collections" android:name="com.majinnaibu.monstercards.ui.collections.CollectionsFragment" android:label="@string/title_collections" - tools:layout="@layout/fragment_collections" > + tools:layout="@layout/fragment_collections"> @@ -39,7 +39,7 @@ android:id="@+id/navigation_library" android:name="com.majinnaibu.monstercards.ui.library.LibraryFragment" android:label="@string/title_library" - tools:layout="@layout/fragment_library" > + tools:layout="@layout/fragment_library"> @@ -47,7 +47,7 @@