diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml index c9d60dd..70129c6 100644 --- a/Android/app/src/main/AndroidManifest.xml +++ b/Android/app/src/main/AndroidManifest.xml @@ -12,6 +12,40 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + + + + + + + + + + + + + + + + + + + + + + + @@ -22,4 +56,5 @@ - \ No newline at end of file + + diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ImportMonsterActivity.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ImportMonsterActivity.java new file mode 100644 index 0000000..030f8cc --- /dev/null +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ImportMonsterActivity.java @@ -0,0 +1,318 @@ +package com.majinnaibu.monstercards; + +import android.content.Intent; +import android.content.res.Resources; +import android.net.Uri; +import android.os.Bundle; +import android.text.Html; +import android.text.Spanned; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Menu; +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.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.ViewModelProvider; + +import com.google.android.material.snackbar.Snackbar; +import com.majinnaibu.monstercards.data.MonsterRepository; +import com.majinnaibu.monstercards.helpers.CommonMarkHelper; +import com.majinnaibu.monstercards.helpers.MonsterImportHelper; +import com.majinnaibu.monstercards.helpers.StringHelper; +import com.majinnaibu.monstercards.models.Monster; +import com.majinnaibu.monstercards.ui.monster.MonsterDetailViewModel; +import com.majinnaibu.monstercards.utils.Logger; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.observers.DisposableCompletableObserver; +import io.reactivex.rxjava3.schedulers.Schedulers; + +public class ImportMonsterActivity extends AppCompatActivity { + + private ViewHolder mHolder; + + private MonsterDetailViewModel mViewModel; + + @Override + protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.fragment_monster); + mHolder = new ViewHolder(findViewById(android.R.id.content)); + mViewModel = new ViewModelProvider(this).get(MonsterDetailViewModel.class); + + 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); + } + + private void setupLabeledTextView(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; + DisplayMetrics displayMetrics = null; + Resources resources = getResources(); + if (resources != null) { + displayMetrics = resources.getDisplayMetrics(); + } + root.removeAllViews(); + for (String action : traits) { + TextView tvAction = new TextView(this); + // 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 boolean onCreateOptionsMenu(@NonNull Menu menu) { + getMenuInflater().inflate(R.menu.import_monster, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == R.id.menu_action_import_monster) { + Logger.logDebug("Menu Item Selected"); + Monster monster = mViewModel.getMonster(); + if (monster != null) { + monster.id = UUID.randomUUID(); + MonsterCardsApplication application = (MonsterCardsApplication) getApplication(); + MonsterRepository repository = application.getMonsterRepository(); + repository.addMonster(monster).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new DisposableCompletableObserver() { + @Override + public void onComplete() { + Snackbar.make( + mHolder.root, + getString(R.string.snackbar_monster_created, monster.name), + Snackbar.LENGTH_LONG) + .setAction("Action", (_view) -> navigateToEditMonster(monster.id)) + .show(); + } + + @Override + public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { + Logger.logError("Error creating monster", e); + Snackbar.make(mHolder.root, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG).show(); + } + }); + } else { + Logger.logWTF("monsterId cannot be null."); + } + return true; + } + return super.onOptionsItemSelected(item); + } + + private void navigateToEditMonster(UUID monsterId) { + Logger.logUnimplementedFeature(String.format("navigate to editing the monster %s", monsterId)); + } + + private static class ViewHolder { + final View root; + 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(View root) { + this.root = 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/helpers/MonsterImportHelper.java b/Android/app/src/main/java/com/majinnaibu/monstercards/helpers/MonsterImportHelper.java index de7e0e8..a25f0dd 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/helpers/MonsterImportHelper.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/helpers/MonsterImportHelper.java @@ -1,7 +1,5 @@ package com.majinnaibu.monstercards.helpers; -import androidx.annotation.NonNull; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -17,16 +15,17 @@ import com.majinnaibu.monstercards.models.Monster; import com.majinnaibu.monstercards.models.Skill; import com.majinnaibu.monstercards.models.Trait; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Set; public class MonsterImportHelper { - @NonNull public static Monster fromJSON(String json) { - JsonObject rootDict = JsonParser.parseString(json).getAsJsonObject(); + JsonParser parser = new JsonParser(); + JsonObject rootDict = parser.parse(json).getAsJsonObject(); Monster monster = new Monster(); monster.name = Helpers.getString(rootDict, "name"); @@ -111,7 +110,7 @@ public class MonsterImportHelper { return getString(dict, name, ""); } - public static String getString(@NonNull JsonObject dict, String name, String defaultValue) { + public static String getString(@NotNull JsonObject dict, String name, String defaultValue) { if (dict.has(name)) { return dict.get(name).getAsString(); } @@ -123,19 +122,13 @@ public class MonsterImportHelper { return getInt(dict, name, 0); } - public static int getInt(@NonNull JsonObject dict, String name, int defaultValue) { + public static int getInt(@NotNull JsonObject dict, String name, int defaultValue) { if (dict.has(name)) { JsonElement element = dict.get(name); if (element.isJsonPrimitive()) { - JsonPrimitive rawValue = element.getAsJsonPrimitive(); + JsonPrimitive rawValue = element.getAsJsonPrimitive();//dict.getAsJsonPrimitive(name); if (rawValue.isNumber()) { return rawValue.getAsInt(); - } else { - try { - return rawValue.getAsInt(); - } catch (Exception ex) { - return defaultValue; - } } } } @@ -146,29 +139,22 @@ public class MonsterImportHelper { return getBool(dict, name, false); } - public static boolean getBool(@NonNull JsonObject dict, String name, boolean defaultValue) { + public static boolean getBool(@NotNull JsonObject dict, String name, boolean defaultValue) { if (dict.has(name)) { JsonElement element = dict.get(name); if (element.isJsonPrimitive()) { JsonPrimitive rawValue = element.getAsJsonPrimitive(); if (rawValue.isBoolean()) { return rawValue.getAsBoolean(); - } else { - try { - return rawValue.getAsBoolean(); - } catch (Exception ex) { - return defaultValue; - } } } } return defaultValue; } - @NonNull + @NotNull public static String formatDistance(String name, int distance) { - // TODO: consider moving this to a string resource so it can be localized - return String.format(Locale.getDefault(), "%s %d ft.", name, distance); + return String.format("%s %d ft.", name, distance); } public static void addSense(Monster monster, JsonObject root, String name) { @@ -178,8 +164,8 @@ public class MonsterImportHelper { } } - @NonNull - public static List getListOfTraits(@NonNull JsonObject dict, String name) { + @NotNull + public static List getListOfTraits(@NotNull JsonObject dict, String name) { ArrayList traits = new ArrayList<>(); if (dict.has(name)) { JsonElement arrayElement = dict.get(name); @@ -191,7 +177,7 @@ public class MonsterImportHelper { if (jsonElement.isJsonObject()) { JsonObject jsonObject = jsonElement.getAsJsonObject(); String traitName = Helpers.getString(jsonObject, "name"); - String description = Helpers.getString(jsonObject, "desc"); + String description = Helpers.getString(jsonObject, "description"); Trait trait = new Trait(traitName, description); traits.add(trait); } @@ -201,7 +187,7 @@ public class MonsterImportHelper { return traits; } - public static void addSavingThrows(Monster monster, @NonNull JsonObject root) { + public static void addSavingThrows(Monster monster, JsonObject root) { if (root.has("sthrows")) { JsonElement arrayElement = root.get("sthrows"); if (arrayElement.isJsonArray()) { @@ -231,8 +217,7 @@ public class MonsterImportHelper { } } - @NonNull - public static Set getSetOfSkills(@NonNull JsonObject root) { + public static Set getSetOfSkills(JsonObject root) { HashSet skills = new HashSet<>(); if (root.has("skills")) { JsonElement arrayElement = root.get("skills"); @@ -256,13 +241,11 @@ public class MonsterImportHelper { return skills; } - @NonNull public static Set getSetOfDamageTypes(JsonObject rootDict, String name) { return getSetOfDamageTypes(rootDict, name, null); } - @NonNull - public static Set getSetOfDamageTypes(@NonNull JsonObject root, String name, String type) { + public static Set getSetOfDamageTypes(JsonObject root, String name, String type) { HashSet damageTypes = new HashSet<>(); if (root.has(name)) { JsonElement arrayElement = root.get(name); @@ -285,8 +268,7 @@ public class MonsterImportHelper { return damageTypes; } - @NonNull - public static Set getSetOfLanguages(@NonNull JsonObject root, String name) { + public static Set getSetOfLanguages(JsonObject root, String name) { HashSet languages = new HashSet<>(); if (root.has(name)) { JsonElement arrayElement = root.get(name); 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 95fbb3d..a0b0bed 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 @@ -12,155 +12,180 @@ 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<>(); - 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(""); - mMonsterId = new MutableLiveData<>(); - mMonsterId.setValue(UUID.fromString("00000000-0000-0000-0000-000000000000")); + 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")); } - private MutableLiveData> mAbilities; public LiveData> getAbilities() { return mAbilities; } - private MutableLiveData> mActions; + public LiveData> getActions() { return mActions; } - private MutableLiveData mArmorClass; + + 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; } - 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 final MutableLiveData mMonsterId; - public LiveData getId() { return mMonsterId; } - private Monster mMonster; + public Monster getMonster() { + return mMonster; + } + public void setMonster(Monster monster) { mMonster = monster; - mAbilities.setValue(mMonster.getAbilityDescriptions()); mActions.setValue(mMonster.getActionDescriptions()); mArmorClass.setValue(mMonster.getArmorClass()); @@ -174,9 +199,14 @@ 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()); @@ -184,4 +214,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/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index aae151f..e0e919e 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ Add Skill Add Trait Edit - Actions + Import Monster MonsterCards CHA CON @@ -26,6 +26,7 @@ None Alignment Armor + Armor Class Base Speed Basic Info Burrow Speed @@ -53,6 +54,7 @@ Has Custom Speed Has a Shield Hit Dice + Hit Points + Intelligence Lair Actions @@ -66,7 +68,7 @@ None Proficient Reactions - Regional Actions + Regional Effects Saving Throws Query Senses