diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java b/Android/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java index 1d50723..0ad8fd5 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/AppDatabase.java @@ -17,7 +17,7 @@ import com.majinnaibu.monstercards.models.Monster; import com.majinnaibu.monstercards.models.MonsterFTS; @SuppressWarnings("unused") -@Database(entities = {Monster.class, MonsterFTS.class}, version = 2) +@Database(entities = {Monster.class, MonsterFTS.class}, version = 3) @TypeConverters({ ArmorTypeConverter.class, ChallengeRatingConverter.class, diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/MonsterCardsApplication.java b/Android/app/src/main/java/com/majinnaibu/monstercards/MonsterCardsApplication.java index 9eab6e7..575720e 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/MonsterCardsApplication.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/MonsterCardsApplication.java @@ -1,7 +1,6 @@ package com.majinnaibu.monstercards; import android.app.Application; -import android.content.Context; import android.content.res.Configuration; import androidx.annotation.NonNull; @@ -14,20 +13,38 @@ import com.majinnaibu.monstercards.init.FlipperInitializer; public class MonsterCardsApplication extends Application { - private AppDatabase m_db; + private static final Migration MIGRATION_1_2 = new Migration(1, 2) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // rename table monster to monsters + database.execSQL("ALTER TABLE monster RENAME TO monsters"); + // create the fts view + database.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `monsters_fts` USING FTS4(`name` TEXT, `size` TEXT, `type` TEXT, `subtype` TEXT, `alignment` TEXT, content=`monsters`)"); + // build the initial full text search index + database.execSQL("INSERT INTO monsters_fts(monsters_fts) VALUES('rebuild')"); + + } + }; + private static final Migration MIGRATION_2_3 = new Migration(2, 3) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + // Add the senses column + database.execSQL("ALTER TABLE monsters ADD COLUMN 'senses' TEXT DEFAULT '[]'"); + database.execSQL("CREATE TABLE new_monsters (`id` TEXT NOT NULL, `name` TEXT NOT NULL DEFAULT '', `size` TEXT NOT NULL DEFAULT '', `type` TEXT NOT NULL DEFAULT '', `subtype` TEXT NOT NULL DEFAULT '', `alignment` TEXT NOT NULL DEFAULT '', `strength_score` INTEGER NOT NULL DEFAULT 10, `strength_saving_throw_advantage` TEXT DEFAULT 'none', `strength_saving_throw_proficiency` TEXT DEFAULT 'none', `dexterity_score` INTEGER NOT NULL DEFAULT 10, `dexterity_saving_throw_advantage` TEXT DEFAULT 'none', `dexterity_saving_throw_proficiency` TEXT DEFAULT 'none', `constitution_score` INTEGER NOT NULL DEFAULT 10, `constitution_saving_throw_advantage` TEXT DEFAULT 'none', `constitution_saving_throw_proficiency` TEXT DEFAULT 'none', `intelligence_score` INTEGER NOT NULL DEFAULT 10, `intelligence_saving_throw_advantage` TEXT DEFAULT 'none', `intelligence_saving_throw_proficiency` TEXT DEFAULT 'none', `wisdom_score` INTEGER NOT NULL DEFAULT 10, `wisdom_saving_throw_advantage` TEXT DEFAULT 'none', `wisdom_saving_throw_proficiency` TEXT DEFAULT 'none', `charisma_score` INTEGER NOT NULL DEFAULT 10, `charisma_saving_throw_advantage` TEXT DEFAULT 'none', `charisma_saving_throw_proficiency` TEXT DEFAULT 'none', `armor_type` TEXT DEFAULT 'none', `shield_bonus` INTEGER NOT NULL DEFAULT 0, `natural_armor_bonus` INTEGER NOT NULL DEFAULT 0, `other_armor_description` TEXT DEFAULT '', `hit_dice` INTEGER NOT NULL DEFAULT 1, `has_custom_hit_points` INTEGER NOT NULL, `custom_hit_points_description` TEXT DEFAULT '', `walk_speed` INTEGER NOT NULL DEFAULT 0, `burrow_speed` INTEGER NOT NULL DEFAULT 0, `climb_speed` INTEGER NOT NULL DEFAULT 0, `fly_speed` INTEGER NOT NULL DEFAULT 0, `can_hover` INTEGER NOT NULL DEFAULT false, `swim_speed` INTEGER NOT NULL DEFAULT 0, `has_custom_speed` INTEGER NOT NULL DEFAULT false, `custom_speed_description` TEXT, `challenge_rating` TEXT DEFAULT '1', `custom_challenge_rating_description` TEXT DEFAULT '', `custom_proficiency_bonus` INTEGER NOT NULL DEFAULT 0, `telepathy_range` INTEGER NOT NULL DEFAULT 0, `understands_but_description` TEXT DEFAULT '', `senses` TEXT DEFAULT '[]', `skills` TEXT DEFAULT '[]', `damage_immunities` TEXT DEFAULT '[]', `damage_resistances` TEXT DEFAULT '[]', `damage_vulnerabilities` TEXT DEFAULT '[]', `condition_immunities` TEXT DEFAULT '[]', `languages` TEXT DEFAULT '[]', `abilities` TEXT DEFAULT '[]', `actions` TEXT DEFAULT '[]', `reactions` TEXT DEFAULT '[]', `lair_actions` TEXT DEFAULT '[]', `legendary_actions` TEXT DEFAULT '[]', `regional_actions` TEXT DEFAULT '[]', PRIMARY KEY(`id`))"); + database.execSQL("INSERT INTO new_monsters(id, name, size, type, subtype, alignment, strength_score, strength_saving_throw_advantage, strength_saving_throw_proficiency, dexterity_score, dexterity_saving_throw_advantage, dexterity_saving_throw_proficiency, constitution_score, constitution_saving_throw_advantage, constitution_saving_throw_proficiency, intelligence_score, intelligence_saving_throw_advantage, intelligence_saving_throw_proficiency, wisdom_score, wisdom_saving_throw_advantage, wisdom_saving_throw_proficiency, charisma_score, charisma_saving_throw_advantage, charisma_saving_throw_proficiency, armor_type, shield_bonus, natural_armor_bonus, other_armor_description, hit_dice, has_custom_hit_points, custom_hit_points_description, walk_speed, burrow_speed, climb_speed, fly_speed, can_hover, swim_speed, has_custom_speed, custom_speed_description, challenge_rating, custom_challenge_rating_description, custom_proficiency_bonus, telepathy_range, understands_but_description, senses, skills, damage_immunities, damage_resistances, damage_vulnerabilities, condition_immunities, languages, abilities, actions, reactions, lair_actions, legendary_actions, regional_actions) SELECT id, name, size, type, subtype, alignment, strength_score, strength_saving_throw_advantage, strength_saving_throw_proficiency, dexterity_score, dexterity_saving_throw_advantage, dexterity_saving_throw_proficiency, constitution_score, constitution_saving_throw_advantage, constitution_saving_throw_proficiency, intelligence_score, intelligence_saving_throw_advantage, intelligence_saving_throw_proficiency, wisdom_score, wisdom_saving_throw_advantage, wisdom_saving_throw_proficiency, charisma_score, charisma_saving_throw_advantage, charisma_saving_throw_proficiency, armor_type, shield_bonus, natural_armor_bonus, other_armor_description, hit_dice, has_custom_hit_points, custom_hit_points_description, walk_speed, burrow_speed, climb_speed, fly_speed, can_hover, swim_speed, has_custom_speed, custom_speed_description, challenge_rating, custom_challenge_rating_description, custom_proficiency_bonus, telepathy_range, understands_but_description, senses, skills, damage_immunities, damage_resistances, damage_vulnerabilities, condition_immunities, languages, abilities, actions, reactions, lair_actions, legendary_actions, regional_actions FROM monsters"); + database.execSQL("DROP TABLE monsters"); + database.execSQL("ALTER TABLE new_monsters RENAME TO monsters"); + } + }; private MonsterRepository m_monsterLibraryRepository; - public MonsterRepository getMonsterRepository() { - return m_monsterLibraryRepository; - } - - public static MonsterCardsApplication getInstance(Context context) { - return (MonsterCardsApplication) context.getApplicationContext(); - } public MonsterCardsApplication() { } + public MonsterRepository getMonsterRepository() { + return m_monsterLibraryRepository; + } // Called when the application is starting, before any other application objects have been created. // Overriding this method is totally optional! @@ -38,9 +55,12 @@ public class MonsterCardsApplication extends Application { FlipperInitializer.init(this); - m_db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "monsters") + // .fallbackToDestructiveMigration() + AppDatabase m_db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "monsters") .addMigrations(MIGRATION_1_2) + .addMigrations(MIGRATION_2_3) .fallbackToDestructiveMigrationOnDowngrade() +// .fallbackToDestructiveMigration() .build(); m_monsterLibraryRepository = new MonsterRepository(m_db); } @@ -59,17 +79,4 @@ public class MonsterCardsApplication extends Application { public void onLowMemory() { super.onLowMemory(); } - - private static final Migration MIGRATION_1_2 = new Migration(1, 2) { - @Override - public void migrate(@NonNull SupportSQLiteDatabase database) { - // rename table monster to monsters - database.execSQL("ALTER TABLE monster RENAME TO monsters"); - // create the fts view - database.execSQL("CREATE VIRTUAL TABLE IF NOT EXISTS `monsters_fts` USING FTS4(`name` TEXT, `size` TEXT, `type` TEXT, `subtype` TEXT, `alignment` TEXT, content=`monsters`)"); - // build the initial full text search index - database.execSQL("INSERT INTO monsters_fts(monsters_fts) VALUES('rebuild')"); - - } - }; } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/data/DevContent.java b/Android/app/src/main/java/com/majinnaibu/monstercards/data/DevContent.java index f337c31..5a3fc5f 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/data/DevContent.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/data/DevContent.java @@ -10,6 +10,7 @@ import com.majinnaibu.monstercards.models.Monster; import com.majinnaibu.monstercards.models.Skill; import com.majinnaibu.monstercards.models.Trait; +@SuppressWarnings("unused") public final class DevContent { public static Monster createSampleMonster() { Monster monster = new Monster(); @@ -80,11 +81,10 @@ public final class DevContent { // Condition Immunities monster.conditionImmunities.add("blinded"); // Senses - monster.blindsightRange = 10; - monster.isBlindBeyondBlindsightRange = true; - monster.darkvisionRange = 20; - monster.tremorsenseRange = 30; - monster.truesightRange = 40; + monster.senses.add("blindsight 10 ft. (blind beyond this range)"); + monster.senses.add("darkvision 20 ft."); + monster.senses.add("tremorsense 30 ft."); + monster.senses.add("truesight 40 ft."); monster.telepathyRange = 20; monster.understandsButDescription = "doesn't care"; // Languages diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java index 1634d28..da50796 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/models/Monster.java @@ -159,61 +159,49 @@ public class Monster { @ColumnInfo(name = "custom_proficiency_bonus", defaultValue = "0") public int customProficiencyBonus; - @ColumnInfo(name = "blindsight_range", defaultValue = "0") - public int blindsightRange; - - @ColumnInfo(name = "is_blind_beyond_blindsight_range", defaultValue = "false") - public boolean isBlindBeyondBlindsightRange; - - @ColumnInfo(name = "darkvision_range", defaultValue = "0") - public int darkvisionRange; - - @ColumnInfo(name = "tremorsense_range", defaultValue = "0") - public int tremorsenseRange; - - @ColumnInfo(name = "truesight_range", defaultValue = "0") - public int truesightRange; - @ColumnInfo(name = "telepathy_range", defaultValue = "0") public int telepathyRange; @ColumnInfo(name = "understands_but_description", defaultValue = "") public String understandsButDescription; - @ColumnInfo(name = "skills") + @ColumnInfo(name = "senses", defaultValue = "[]") + public Set senses; + + @ColumnInfo(name = "skills", defaultValue = "[]") public Set skills; - @ColumnInfo(name = "damage_immunities") + @ColumnInfo(name = "damage_immunities", defaultValue = "[]") public Set damageImmunities; - @ColumnInfo(name = "damage_resistances") + @ColumnInfo(name = "damage_resistances", defaultValue = "[]") public Set damageResistances; - @ColumnInfo(name = "damage_vulnerabilities") + @ColumnInfo(name = "damage_vulnerabilities", defaultValue = "[]") public Set damageVulnerabilities; - @ColumnInfo(name = "condition_immunities") + @ColumnInfo(name = "condition_immunities", defaultValue = "[]") public Set conditionImmunities; - @ColumnInfo(name = "languages") + @ColumnInfo(name = "languages", defaultValue = "[]") public Set languages; - @ColumnInfo(name = "abilities") + @ColumnInfo(name = "abilities", defaultValue = "[]") public Set abilities; - @ColumnInfo(name = "actions") + @ColumnInfo(name = "actions", defaultValue = "[]") public Set actions; - @ColumnInfo(name = "reactions") + @ColumnInfo(name = "reactions", defaultValue = "[]") public Set reactions; - @ColumnInfo(name = "lair_actions") + @ColumnInfo(name = "lair_actions", defaultValue = "[]") public Set lairActions; - @ColumnInfo(name = "legendary_actions") + @ColumnInfo(name = "legendary_actions", defaultValue = "[]") public Set legendaryActions; - @ColumnInfo(name = "regional_actions") + @ColumnInfo(name = "regional_actions", defaultValue = "[]") public Set regionalActions; public Monster() { @@ -246,8 +234,25 @@ public class Monster { customSpeedDescription = ""; challengeRating = ChallengeRating.ONE; customChallengeRatingDescription = ""; + customProficiencyBonus = 0; + telepathyRange = 0; + understandsButDescription = ""; + strengthSavingThrowAdvantage = AdvantageType.NONE; + strengthSavingThrowProficiency = ProficiencyType.NONE; + dexteritySavingThrowAdvantage = AdvantageType.NONE; + dexteritySavingThrowProficiency = ProficiencyType.NONE; + constitutionSavingThrowAdvantage = AdvantageType.NONE; + constitutionSavingThrowProficiency = ProficiencyType.NONE; + intelligenceSavingThrowAdvantage = AdvantageType.NONE; + intelligenceSavingThrowProficiency = ProficiencyType.NONE; + wisdomSavingThrowAdvantage = AdvantageType.NONE; + wisdomSavingThrowProficiency = ProficiencyType.NONE; + charismaSavingThrowAdvantage = AdvantageType.NONE; + charismaSavingThrowProficiency = ProficiencyType.NONE; + skills = new HashSet<>(); + senses = new HashSet<>(); damageImmunities = new HashSet<>(); damageResistances = new HashSet<>(); damageVulnerabilities = new HashSet<>(); @@ -630,21 +635,8 @@ public class Monster { } public String getSensesDescription() { - ArrayList parts = new ArrayList<>(); - if (blindsightRange > 0) { - parts.add(String.format("blindsight %d ft.%s", blindsightRange, isBlindBeyondBlindsightRange ? " (blind beyond this radius)" : "")); - } - if (darkvisionRange > 0) { - parts.add(String.format("darkvision %d ft.", darkvisionRange)); - } - if (tremorsenseRange > 0) { - parts.add(String.format("tremorsense %d ft.", tremorsenseRange)); - } - if (truesightRange > 0) { - parts.add(String.format("truesight %d ft.", truesightRange)); - } + ArrayList parts = new ArrayList<>(senses); parts.add(String.format("passive Perception %d", 10 + getWisdomModifier())); - return StringHelper.join(", ", parts); } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java index d9b34dd..6fa13a8 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java @@ -18,8 +18,10 @@ import com.majinnaibu.monstercards.models.Trait; import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -72,14 +74,10 @@ public class EditMonsterViewModel extends ViewModel { private final ChangeTrackedLiveData mChallengeRating; private final ChangeTrackedLiveData mCustomChallengeRatingDescription; private final ChangeTrackedLiveData mCustomProficiencyBonus; - private final ChangeTrackedLiveData mBlindsightRange; - private final ChangeTrackedLiveData mIsBlindBeyondBlindsightRange; - private final ChangeTrackedLiveData mDarkvisionRange; - private final ChangeTrackedLiveData mTremorsenseRange; - private final ChangeTrackedLiveData mTruesightRange; private final ChangeTrackedLiveData mTelepathyRange; private final ChangeTrackedLiveData mUnderstandsButDescription; private final ChangeTrackedLiveData> mSkills; + private final ChangeTrackedLiveData> mSenses; private final ChangeTrackedLiveData> mDamageImmunities; private final ChangeTrackedLiveData> mDamageResistances; private final ChangeTrackedLiveData> mDamageVulnerabilities; @@ -142,14 +140,10 @@ public class EditMonsterViewModel extends ViewModel { mChallengeRating = new ChangeTrackedLiveData<>(ChallengeRating.ONE_EIGHTH, onDirtied); mCustomChallengeRatingDescription = new ChangeTrackedLiveData<>("", onDirtied); mCustomProficiencyBonus = new ChangeTrackedLiveData<>(0, onDirtied); - mBlindsightRange = new ChangeTrackedLiveData<>(0, onDirtied); - mIsBlindBeyondBlindsightRange = new ChangeTrackedLiveData<>(false, onDirtied); - mDarkvisionRange = new ChangeTrackedLiveData<>(0, onDirtied); - mTremorsenseRange = new ChangeTrackedLiveData<>(0, onDirtied); - mTruesightRange = new ChangeTrackedLiveData<>(0, onDirtied); mTelepathyRange = new ChangeTrackedLiveData<>(0, onDirtied); mUnderstandsButDescription = new ChangeTrackedLiveData<>("", onDirtied); mSkills = new ChangeTrackedLiveData<>(new ArrayList<>(), onDirtied); + mSenses = new ChangeTrackedLiveData<>(new ArrayList<>(), onDirtied); mDamageImmunities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); mDamageResistances = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); mDamageVulnerabilities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); @@ -207,22 +201,15 @@ public class EditMonsterViewModel extends ViewModel { mChallengeRating.resetValue(monster.challengeRating); mCustomChallengeRatingDescription.resetValue(monster.customChallengeRatingDescription); mCustomProficiencyBonus.resetValue(monster.customProficiencyBonus); - mBlindsightRange.resetValue(monster.blindsightRange); - mIsBlindBeyondBlindsightRange.resetValue(monster.isBlindBeyondBlindsightRange); - mDarkvisionRange.resetValue(monster.darkvisionRange); - mTremorsenseRange.resetValue(monster.tremorsenseRange); - mTruesightRange.resetValue(monster.truesightRange); mTelepathyRange.resetValue(monster.telepathyRange); mUnderstandsButDescription.resetValue(monster.understandsButDescription); - if (monster.skills.size() == 0) { - ArrayList skills = new ArrayList<>(); - skills.add(new Skill("Acrobatics", AbilityScore.STRENGTH)); - skills.add(new Skill("Stealth", AbilityScore.DEXTERITY)); - mSkills.resetValue(skills); - } else { - mSkills.resetValue(new ArrayList<>(monster.skills)); - } + ArrayList skills = new ArrayList<>(monster.skills); + Collections.sort(skills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); + mSkills.resetValue(skills); + ArrayList senses = new ArrayList<>(monster.senses); + Collections.sort(senses, String::compareToIgnoreCase); + mSenses.resetValue(senses); mDamageImmunities.resetValue(monster.damageImmunities); mDamageResistances.resetValue(monster.damageResistances); mDamageVulnerabilities.resetValue(monster.damageVulnerabilities); @@ -749,46 +736,6 @@ public class EditMonsterViewModel extends ViewModel { return mCustomProficiencyBonus.getValue().toString(); } - public LiveData getBlindsightRange() { - return mBlindsightRange; - } - - public void setBlindsightRange(int blindsightRange) { - mBlindsightRange.setValue(blindsightRange); - } - - public LiveData getIsBlindBeyondBlindsightRange() { - return mIsBlindBeyondBlindsightRange; - } - - public void setIsBlindBeyondBlindsightRange(boolean isBlindBeyondBlindsightRange) { - mIsBlindBeyondBlindsightRange.setValue(isBlindBeyondBlindsightRange); - } - - public LiveData getDarkvisionRange() { - return mDarkvisionRange; - } - - public void setDarkvisionRange(int darkvisionRange) { - mDarkvisionRange.setValue(darkvisionRange); - } - - public LiveData getTremorsenseRange() { - return mTremorsenseRange; - } - - public void setTremorsenseRange(int tremorsenseRange) { - mTremorsenseRange.setValue(tremorsenseRange); - } - - public LiveData getTruesightRange() { - return mTruesightRange; - } - - public void setTruesightRange(int truesightRange) { - mTruesightRange.setValue(truesightRange); - } - public LiveData getTelepathyRange() { return mTelepathyRange; } @@ -809,22 +756,14 @@ public class EditMonsterViewModel extends ViewModel { return mSkills; } - /* - // TODO: add getters and setters for - Senses - Skills - Damage Immunities - DamageResistances - DamageVulnerabilities - ConditionImmunities - Languages - Abilities - Actions - Reactions - LairActions - LegendaryActions - RegionalActions - */ + public List getSensesArray() { + return mSenses.getValue(); + } + + // TODO: add getters and setters for lists of strings (Senses, Damage Immunities, Damage Resistances, Damage Vulnerabilities, and Condition Immunities) + // TODO: add getters and setters for Languages + // TODO: add getters and setters for traits (Abilities, Actions, Reactions, Lair Actions, Legendary Actions, and Regional Actions) + public Monster buildMonster() { Monster monster = new Monster(); @@ -870,14 +809,10 @@ public class EditMonsterViewModel extends ViewModel { monster.challengeRating = mChallengeRating.getValue(); monster.customChallengeRatingDescription = mCustomChallengeRatingDescription.getValue(); monster.customProficiencyBonus = mCustomProficiencyBonus.getValue(); - monster.blindsightRange = mBlindsightRange.getValue(); - monster.isBlindBeyondBlindsightRange = mIsBlindBeyondBlindsightRange.getValue(); - monster.darkvisionRange = mDarkvisionRange.getValue(); - monster.tremorsenseRange = mTremorsenseRange.getValue(); - monster.truesightRange = mTruesightRange.getValue(); monster.telepathyRange = mTelepathyRange.getValue(); monster.understandsButDescription = mUnderstandsButDescription.getValue(); monster.skills = new HashSet<>(mSkills.getValue()); + monster.senses = new HashSet<>(mSenses.getValue()); monster.damageImmunities = mDamageImmunities.getValue(); monster.damageResistances = mDamageResistances.getValue(); monster.damageVulnerabilities = mDamageVulnerabilities.getValue(); @@ -897,10 +832,41 @@ public class EditMonsterViewModel extends ViewModel { return mSkills.getValue(); } - public void addNewSkill() { + public Skill addNewSkill() { Skill newSkill = new Skill("Unnamed Skill", AbilityScore.DEXTERITY); ArrayList newSkills = new ArrayList<>(mSkills.getValue()); newSkills.add(newSkill); + Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); + mSkills.setValue(newSkills); + return newSkill; + } + + public void removeSkill(int position) { + List skills = mSkills.getValue(); + ArrayList newSkills = new ArrayList<>(skills); + newSkills.remove(position); + mSkills.setValue(newSkills); + } + + public void replaceSkill(Skill newSkill, Skill oldSkill) { + List oldSkills = mSkills.getValue(); + if (oldSkills == null) { + oldSkills = new ArrayList<>(); + } + boolean hasReplaced = false; + ArrayList newSkills = new ArrayList<>(oldSkills.size()); + for (Skill skill : oldSkills) { + if (Objects.equals(skill, oldSkill)) { + newSkills.add(newSkill); + hasReplaced = true; + } else { + newSkills.add(skill); + } + } + if (!hasReplaced) { + newSkills.add(newSkill); + } + Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); mSkills.setValue(newSkills); } }