From 75cd32b0d8a4a0873fed40b91a4051dcc4e97b9f Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Wed, 30 Jun 2021 23:24:46 -0700 Subject: [PATCH] Makes monster importing a fragment in the main activity. Makes the edit action work when editing an imported monster. --- app/src/main/AndroidManifest.xml | 24 +- .../majinnaibu/monstercards/MainActivity.java | 67 +++++- .../ui/monster/MonsterDetailViewModel.java | 4 - .../monster/MonsterImportFragment.java} | 180 ++++++--------- .../ui/monster/MonsterImportViewModel.java | 216 ++++++++++++++++++ .../main/res/navigation/mobile_navigation.xml | 17 ++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 380 insertions(+), 129 deletions(-) rename app/src/main/java/com/majinnaibu/monstercards/{ImportMonsterActivity.java => ui/monster/MonsterImportFragment.java} (57%) create mode 100644 app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterImportViewModel.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 57a954b..eaa2137 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,19 +5,22 @@ + android:name=".MainActivity" + android:label="@string/app_name" + android:launchMode="singleTask"> + + + + + @@ -45,15 +48,8 @@ android:mimeType="text/plain" android:scheme="file" /> - - - - - - + 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)); - mViewModel.getName().observe(this, mHolder.name::setText); - mViewModel.getMeta().observe(this, mHolder.meta::setText); - mViewModel.getArmorClass().observe(this, armorText -> setupLabeledTextView(mHolder.armorClass, armorText, R.string.label_armor_class)); - mViewModel.getHitPoints().observe(this, hitPoints -> setupLabeledTextView(mHolder.hitPoints, hitPoints, R.string.label_hit_points)); - mViewModel.getSpeed().observe(this, speed -> setupLabeledTextView(mHolder.speed, speed, R.string.label_speed)); - mViewModel.getStrength().observe(this, mHolder.strength::setText); - mViewModel.getDexterity().observe(this, mHolder.dexterity::setText); - mViewModel.getConstitution().observe(this, mHolder.constitution::setText); - mViewModel.getIntelligence().observe(this, mHolder.intelligence::setText); - mViewModel.getWisdom().observe(this, mHolder.wisdom::setText); - mViewModel.getCharisma().observe(this, mHolder.charisma::setText); - mViewModel.getSavingThrows().observe(this, savingThrows -> setupOptionalTextView(mHolder.savingThrows, savingThrows, R.string.label_saving_throws)); - mViewModel.getSkills().observe(this, skills -> setupOptionalTextView(mHolder.skills, skills, R.string.label_skills)); - mViewModel.getDamageVulnerabilities().observe(this, damageTypes -> setupOptionalTextView(mHolder.damageVulnerabilities, damageTypes, R.string.label_damage_vulnerabilities)); - mViewModel.getDamageResistances().observe(this, damageTypes -> setupOptionalTextView(mHolder.damageResistances, damageTypes, R.string.label_damage_resistances)); - mViewModel.getDamageImmunities().observe(this, damageTypes -> setupOptionalTextView(mHolder.damageImmunities, damageTypes, R.string.label_damage_immunities)); - mViewModel.getConditionImmunities().observe(this, conditionImmunities -> setupOptionalTextView(mHolder.conditionImmunities, conditionImmunities, R.string.label_condition_immunities)); - mViewModel.getSenses().observe(this, senses -> setupOptionalTextView(mHolder.senses, senses, R.string.label_senses)); - mViewModel.getLanguages().observe(this, languages -> setupOptionalTextView(mHolder.languages, languages, R.string.label_languages)); - mViewModel.getChallenge().observe(this, challengeRating -> setupLabeledTextView(mHolder.challenge, challengeRating, R.string.label_challenge_rating)); - mViewModel.getAbilities().observe(this, abilities -> setupTraitList(mHolder.abilities, abilities)); - mViewModel.getActions().observe(this, actions -> setupTraitList(mHolder.actions, actions, mHolder.actions_label, mHolder.actions_divider)); - mViewModel.getReactions().observe(this, reactions -> setupTraitList(mHolder.reactions, reactions, mHolder.reactions_label, mHolder.reactions_divider)); - mViewModel.getRegionalEffects().observe(this, regionalEffects -> setupTraitList(mHolder.regionalEffects, regionalEffects, mHolder.regionalEffects_label, mHolder.regionalEffects_divider)); - mViewModel.getLairActions().observe(this, lairActions -> setupTraitList(mHolder.lairActions, lairActions, mHolder.lairActions_label, mHolder.lairActions_divider)); - mViewModel.getLegendaryActions().observe(this, legendaryActions -> setupTraitList(mHolder.legendaryActions, legendaryActions, mHolder.legendaryActions_label, mHolder.legendaryActions_divider)); - } - - @Override - protected void onResume() { - super.onResume(); - Logger.logDebug("onCreateView"); - Monster monster = readMonsterFromIntent(getIntent()); - if (monster != null) { - mViewModel.setMonster(monster); - } - } - - private Monster readMonsterFromIntent(Intent intent) { - String action = intent.getAction(); - Bundle extras = intent.getExtras(); - String type = intent.getType(); - String json; - Uri uri = null; - if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) { - uri = extras.getParcelable("android.intent.extra.STREAM"); - } else if ("android.intent.action.VIEW".equals(action) && ("text/plain".equals(type) || "application/octet-stream".equals(type))) { - uri = intent.getData(); - } else { - Logger.logError(String.format("unexpected launch configuration action: %s, type: %s, uri: %s", action, type, uri)); - } - if (uri == null) { - return null; - } - json = readContentsOfUri(uri); - if (StringHelper.isNullOrEmpty(json)) { - return null; - } - return MonsterImportHelper.fromJSON(json); - } - - private String readContentsOfUri(Uri uri) { - StringBuilder builder = new StringBuilder(); - try (InputStream inputStream = - getContentResolver().openInputStream(uri); - BufferedReader reader = new BufferedReader( - new InputStreamReader(Objects.requireNonNull(inputStream)))) { - String line; - while ((line = reader.readLine()) != null) { - builder.append(line); - } - } catch (IOException e) { - Logger.logError("error reading file", e); - return null; - } - return builder.toString(); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); + return root; } private void setupLabeledTextView(TextView view, String text, int titleId) { @@ -167,14 +116,17 @@ public class ImportMonsterActivity extends AppCompatActivity { 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; - Resources resources = getResources(); - if (resources != null) { - displayMetrics = resources.getDisplayMetrics(); + if (context != null) { + Resources resources = context.getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); + } } root.removeAllViews(); for (String action : traits) { - TextView tvAction = new TextView(this); + 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))); @@ -193,9 +145,9 @@ public class ImportMonsterActivity extends AppCompatActivity { } @Override - public boolean onCreateOptionsMenu(@NonNull Menu menu) { - getMenuInflater().inflate(R.menu.import_monster, menu); - return true; + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + inflater.inflate(R.menu.import_monster, menu); + super.onCreateOptionsMenu(menu, inflater); } @Override @@ -233,7 +185,14 @@ public class ImportMonsterActivity extends AppCompatActivity { } private void navigateToEditMonster(UUID monsterId) { - Logger.logUnimplementedFeature(String.format("navigate to editing the monster %s", monsterId)); + NavController navController = Navigation.findNavController(requireView()); + NavDirections action; + action = MonsterImportFragmentDirections.actionMonsterImportFragmentToNavigationLibrary(); + navController.navigate(action); + action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monsterId.toString()); + navController.navigate(action); + action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString()); + navController.navigate(action); } private static class ViewHolder { @@ -315,4 +274,5 @@ public class ImportMonsterActivity extends AppCompatActivity { regionalEffects_label = root.findViewById(R.id.regionalEffects_label); } } + } diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterImportViewModel.java b/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterImportViewModel.java new file mode 100644 index 0000000..31e1a80 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterImportViewModel.java @@ -0,0 +1,216 @@ +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; +import java.util.UUID; + +public class MonsterImportViewModel 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 MonsterImportViewModel() { + 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")); + } + + public LiveData> getAbilities() { + return mAbilities; + } + + 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; + } + + public LiveData getArmorClass() { + return mArmorClass; + } + + public LiveData getChallenge() { + return mChallenge; + } + + public LiveData getCharisma() { + return mCharisma; + } + + public LiveData getConditionImmunities() { + return mConditionImmunities; + } + + public LiveData getConstitution() { + return mConstitution; + } + + public LiveData getDamageResistances() { + return mDamageResistances; + } + + public LiveData getDamageImmunities() { + return mDamageImmunities; + } + + public LiveData getDamageVulnerabilities() { + return mDamageVulnerabilities; + } + + public LiveData getDexterity() { + return mDexterity; + } + + public LiveData getHitPoints() { + return mHitPoints; + } + + public LiveData getIntelligence() { + return mIntelligence; + } + + public LiveData getLanguages() { + return mLanguages; + } + + public LiveData getMeta() { + return mMeta; + } + + public LiveData getName() { + return mName; + } + + public LiveData getSavingThrows() { + return mSavingThrows; + } + + public LiveData getSenses() { + return mSenses; + } + + public LiveData getSkills() { + return mSkills; + } + + public LiveData getSpeed() { + return mSpeed; + } + + public LiveData getStrength() { + return mStrength; + } + + public LiveData getWisdom() { + return mWisdom; + } + + public LiveData getId() { + return mMonsterId; + } + + public Monster getMonster() { + return 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()); + 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()); + mSpeed.setValue(mMonster.getSpeedText()); + mStrength.setValue(monster.getStrengthDescription()); + mWisdom.setValue(monster.getWisdomDescription()); + } +} diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 893f689..71cb792 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -228,4 +228,21 @@ app:argType="string" /> + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e0e919e..dc5d036 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -121,6 +121,7 @@ Senses Skill Skills + Import Monster Library Search WIS