Compare commits
240 Commits
main
...
70b7a4e795
| Author | SHA1 | Date | |
|---|---|---|---|
| 70b7a4e795 | |||
| 8b4d9b6b17 | |||
| 6bad5a4ed5 | |||
| 93bf987bb9 | |||
| be433bf217 | |||
| 1ae81b03b0 | |||
| 4633a50bf4 | |||
| 9ac73337af | |||
| 25340cb7fd | |||
| be544f5304 | |||
| 3dc39ad6a4 | |||
| 92ea5b6a0d | |||
| a5eec5c4c8 | |||
| e598b2984a | |||
|
|
32ae8461b7 | ||
|
|
8686dbdaea | ||
|
|
a8df37325f | ||
|
|
2743a8337b | ||
|
|
b4767676d2 | ||
|
|
7c9037af84 | ||
|
|
c582ba5eaa | ||
|
|
8b2ab8f48f | ||
|
|
2de07c54cc | ||
|
|
c50f79c273 | ||
|
|
921a02f953 | ||
|
|
ec712842ca | ||
|
|
2f9dec4d02 | ||
|
|
cb1e3343c9 | ||
| 5bded410d2 | |||
| f6a032844c | |||
| d214d615e5 | |||
| 54f863ee5f | |||
| d4d298fcc3 | |||
| 7f31d98d7e | |||
| 68348b18c2 | |||
| 42a2994f2c | |||
| 218f39f6c2 | |||
| 2512bd8d75 | |||
| 370d416a23 | |||
| 60d139078b | |||
| 611fa6c323 | |||
| ab5a3c7c67 | |||
| b889857e80 | |||
| da0e072a45 | |||
| e075fc4369 | |||
| 0db46ebb51 | |||
| 20318b0ad5 | |||
| 6debb1eb27 | |||
| 87c845bd0d | |||
| f507f9d7cd | |||
| 8bb1f64e9f | |||
| f2d0e93911 | |||
| c9a7e028ae | |||
| 807871fe5c | |||
| acadf2170c | |||
| 8215d2021c | |||
| 0cbf6022c4 | |||
| eec695bfc8 | |||
| 8363912e53 | |||
| 67db8d79d0 | |||
| b5834f3db2 | |||
| ca6a319bd9 | |||
| 95ba20b5c6 | |||
| ea65692b38 | |||
| d7cf01e30d | |||
| 30c6dc7ee5 | |||
| f13be2c1ac | |||
| 920344b5fd | |||
| 7b3d6003d4 | |||
| c837c19b87 | |||
| b9759f6364 | |||
| f24f1d978c | |||
| 2defd1fca1 | |||
| 07f81a5f6d | |||
| 985c2fb730 | |||
| 0dc96a8c45 | |||
| 10bca503e5 | |||
| 1d335e9a37 | |||
| fbf119fb8a | |||
| 3d6adaad2c | |||
| c3a972571a | |||
| 4e45a547f4 | |||
| 792628d4a4 | |||
| b6b669a0db | |||
| 540a0474da | |||
| 49734d5eef | |||
| b2c3728e9a | |||
| 39cab7f799 | |||
|
|
1e007a3553 | ||
|
|
1a487f950d | ||
|
|
ea13e38402 | ||
|
|
8e2372085d | ||
|
|
129d910126 | ||
|
|
1a23e5e35a | ||
|
|
660cf633da | ||
|
|
1e7a7c68aa | ||
|
|
070fda0989 | ||
|
|
af05c41b75 | ||
|
|
efa4c2a299 | ||
|
|
2f5918b7a2 | ||
|
|
cb6f7122ed | ||
|
|
7cfc6d4f65 | ||
|
|
cdae6a8b39 | ||
|
|
9d46d1420e | ||
|
|
6d43b0635c | ||
|
|
4c138ee499 | ||
|
|
0fcfa7e782 | ||
|
|
791cf4164c | ||
|
|
fb12deaa3e | ||
|
|
6e597462ef | ||
|
|
12ffc5b15f | ||
|
|
9c81bd4905 | ||
|
|
f1cbc60857 | ||
|
|
a2798ddc82 | ||
|
|
ecf2b01723 | ||
|
|
18d6f2a31e | ||
|
|
7cbcf8d07c | ||
|
|
dc487d238a | ||
|
|
b8c702f665 | ||
|
|
259b59f519 | ||
|
|
5289bac908 | ||
|
|
34e11d97e5 | ||
|
|
ca6684a093 | ||
|
|
6e48a6f455 | ||
| b8af70406f | |||
| 7eae6f820e | |||
| 2076d53b11 | |||
| e20602cc3d | |||
| 04dc066191 | |||
| 72b3df429f | |||
| 8d94afeb55 | |||
| 8bae59ed29 | |||
| c401b7919e | |||
| 9983ba10cb | |||
| 171bc7436e | |||
| 04a30aa766 | |||
| 2356726e3f | |||
| 6151ad889c | |||
| 1f15d73573 | |||
| 40589f171d | |||
| a58c851240 | |||
| 2c6b514538 | |||
| f6a8b83343 | |||
| eb3fa5108f | |||
| 922db42322 | |||
| 71177b92f9 | |||
| 34e68443ae | |||
| 857733ec9c | |||
| 7e78ad8b7d | |||
| 430fa61be1 | |||
| 70e05cbb21 | |||
| b67073622f | |||
| c90579903d | |||
| 1a02eab07a | |||
| 00463c8092 | |||
| 153c49fe7b | |||
| 8178ec6fd7 | |||
| 2e7e40554d | |||
| 989440de83 | |||
| 3c4adacc17 | |||
| c28e1cb8c5 | |||
| 48dab535e9 | |||
| ff26cb64b7 | |||
| 28f0787020 | |||
| 71da064423 | |||
| 23bcdc237d | |||
| b56a662c9e | |||
| dcce64f91a | |||
| 595ee0c6fb | |||
| d52102d430 | |||
| 6a4abdd547 | |||
| bd3741af2d | |||
| e254adfdce | |||
| 9c973ef348 | |||
| dc9a0827d4 | |||
| b27274928e | |||
| 6bb1e419c8 | |||
| 3cda90eedd | |||
| 98a7dc5eeb | |||
| e384e29570 | |||
| 7aa6419ece | |||
| 6b953e320d | |||
| 9f56f0283a | |||
| b5f92afae9 | |||
| f58243ef6b | |||
| 886778ee78 | |||
| 0a85324734 | |||
| b374dbfe71 | |||
| 21af6e20ba | |||
| dc9066daca | |||
| e8e19d5371 | |||
| c5242b5206 | |||
| ac2e37e494 | |||
| c5d857435d | |||
| a1fab9d399 | |||
| e02e4ec399 | |||
| 8706240fb4 | |||
| e17c492baf | |||
| 2df11701e6 | |||
| c6c0e4f758 | |||
| 8c233a3bc7 | |||
| e98b72ad7d | |||
| 1fb8dc3a86 | |||
| 8b52b0c3e5 | |||
| ee065d7b39 | |||
| 59b319c27d | |||
| cdcb7a60d4 | |||
| 79106ec9f3 | |||
| bb4cbbb98b | |||
| 84b0fee261 | |||
| 0c3ab6dc39 | |||
| a694205c74 | |||
| 793987c3fb | |||
| 7d5f9c89a9 | |||
| 6da0bfe70a | |||
| a44893bca8 | |||
| 67375292a5 | |||
| 145c827417 | |||
| 8ff1cb8779 | |||
| 706b58fd2c | |||
| 15973a79f0 | |||
| 94edc44044 | |||
| 5396b7b014 | |||
| e0cc8560d1 | |||
| c627bb0873 | |||
| 6d8ec92012 | |||
| 212358e41d | |||
| 5fca394f0e | |||
| 6c914fb947 | |||
| 5a283b8dae | |||
| 407987e410 | |||
| 27a1dd7580 | |||
| 775fbf3d9b | |||
| 2a75de4bce | |||
| 72502b3d03 | |||
| 2b8a178c05 | |||
| ab306289bd | |||
| 74b0c6695f | |||
| 44d90ff5ea | |||
| 5113283550 |
1
Android/.gitignore
vendored
1
Android/.gitignore
vendored
@@ -8,6 +8,7 @@
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
/.idea/dictionaries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
||||
2
Android/.idea/compiler.xml
generated
2
Android/.idea/compiler.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
</component>
|
||||
</project>
|
||||
2
Android/.idea/gradle.xml
generated
2
Android/.idea/gradle.xml
generated
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
@@ -15,7 +14,6 @@
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
<option name="useQualifiedModuleNames" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
5
Android/.idea/jarRepositories.xml
generated
5
Android/.idea/jarRepositories.xml
generated
@@ -21,10 +21,5 @@
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
19
Android/.idea/misc.xml
generated
19
Android/.idea/misc.xml
generated
@@ -1,5 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="app/src/main/res/layout/dropdown_list_item.xml" value="0.12777777777777777" />
|
||||
<entry key="app/src/main/res/layout/fragment_dashboard_list_item.xml" value="0.2210144927536232" />
|
||||
<entry key="app/src/main/res/layout/fragment_edit_strings_list.xml" value="0.2210144927536232" />
|
||||
<entry key="app/src/main/res/layout/fragment_edit_strings_list_item.xml" value="0.2210144927536232" />
|
||||
<entry key="app/src/main/res/layout/fragment_edit_traits_list.xml" value="0.2210144927536232" />
|
||||
<entry key="app/src/main/res/layout/fragment_edit_traits_list_item.xml" value="0.2210144927536232" />
|
||||
<entry key="app/src/main/res/layout/fragment_search.xml" value="0.16875" />
|
||||
<entry key="app/src/main/res/layout/simple_list_item.xml" value="0.2210144927536232" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="androidx.annotation.Nullable" />
|
||||
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
|
||||
@@ -25,7 +39,7 @@
|
||||
</option>
|
||||
<option name="myNotNulls">
|
||||
<value>
|
||||
<list size="13">
|
||||
<list size="14">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||
<item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||
<item index="2" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||
@@ -39,11 +53,12 @@
|
||||
<item index="10" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
|
||||
<item index="11" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
|
||||
<item index="12" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
|
||||
<item index="13" class="java.lang.String" itemvalue="lombok.NonNull" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
1
Android/.idea/runConfigurations.xml
generated
1
Android/.idea/runConfigurations.xml
generated
@@ -3,7 +3,6 @@
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
|
||||
1
Android/.idea/saveactions_settings.xml
generated
1
Android/.idea/saveactions_settings.xml
generated
@@ -9,7 +9,6 @@
|
||||
<option value="noActionIfCompileErrors" />
|
||||
<option value="organizeImports" />
|
||||
<option value="reformat" />
|
||||
<option value="rearrange" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="configurationPath" value="" />
|
||||
|
||||
4
Android/README.md
Normal file
4
Android/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
[](https://appcenter.ms)
|
||||
|
||||
# MonsterCards for Android
|
||||
|
||||
@@ -21,7 +21,7 @@ def gson_version = '2.8.6'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '30.0.3'
|
||||
buildToolsVersion '30.0.2'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.majinnaibu.monstercards"
|
||||
@@ -70,21 +70,21 @@ dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
|
||||
// Google
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation "androidx.navigation:navigation-fragment:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui:$nav_version"
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
|
||||
// Testing
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
|
||||
// Room DB
|
||||
implementation "io.reactivex.rxjava3:rxjava:$rxjava_version"
|
||||
|
||||
@@ -51,9 +51,6 @@
|
||||
|
||||
<nav-graph android:value="@navigation/mobile_navigation" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
||||
android:exported="true" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
package com.majinnaibu.monstercards;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.room.TypeConverters;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import com.majinnaibu.monstercards.data.MonsterDAO;
|
||||
import com.majinnaibu.monstercards.data.converters.ArmorTypeConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.ChallengeRatingConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.ListOfTraitsConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfLanguageConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfSavingThrowConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfSkillConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfStringConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.UUIDConverter;
|
||||
@@ -21,10 +28,53 @@ import com.majinnaibu.monstercards.models.MonsterFTS;
|
||||
ChallengeRatingConverter.class,
|
||||
ListOfTraitsConverter.class,
|
||||
SetOfLanguageConverter.class,
|
||||
SetOfSavingThrowConverter.class,
|
||||
SetOfSkillConverter.class,
|
||||
SetOfStringConverter.class,
|
||||
UUIDConverter.class,
|
||||
})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
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 static AppDatabase mDB = null;
|
||||
|
||||
public static AppDatabase getInstance(Context context) {
|
||||
if (mDB == null) {
|
||||
synchronized (AppDatabase.class) {
|
||||
if (mDB == null) {
|
||||
// .fallbackToDestructiveMigration()
|
||||
mDB = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "monsters")
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.fallbackToDestructiveMigrationOnDowngrade()
|
||||
// .fallbackToDestructiveMigration()
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mDB;
|
||||
}
|
||||
|
||||
public abstract MonsterDAO monsterDAO();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavDirections;
|
||||
@@ -55,7 +54,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
.build();
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
|
||||
NavController navController = navHostFragment.getNavController();
|
||||
navController.addOnDestinationChangedListener(FlipperInitializer::sendNavigationEvent);
|
||||
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
|
||||
FlipperInitializer.sendNavigationEvent(controller, destination, arguments);
|
||||
});
|
||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
|
||||
NavigationUI.setupWithNavController(navView, navController);
|
||||
onNewIntent(getIntent());
|
||||
@@ -67,15 +68,14 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
String json = readMonsterJSONFromIntent(intent);
|
||||
if (!StringHelper.isNullOrEmpty(json)) {
|
||||
NavHostFragment navHostFragment = Objects.requireNonNull((NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment));
|
||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
|
||||
NavController navController = navHostFragment.getNavController();
|
||||
NavDirections action = MobileNavigationDirections.actionGlobalMonsterImportFragment(json);
|
||||
navController.navigate(action);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String readMonsterJSONFromIntent(@NonNull Intent intent) {
|
||||
private String readMonsterJSONFromIntent(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Bundle extras = intent.getExtras();
|
||||
String type = intent.getType();
|
||||
@@ -86,7 +86,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
} 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", action, type));
|
||||
Logger.logError(String.format("unexpected launch configuration action: %s, type: %s, uri: %s", action, type, uri));
|
||||
}
|
||||
if (uri == null) {
|
||||
return null;
|
||||
@@ -98,7 +98,6 @@ public class MainActivity extends AppCompatActivity {
|
||||
return json;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String readContentsOfUri(Uri uri) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (InputStream inputStream =
|
||||
|
||||
@@ -3,39 +3,12 @@ package com.majinnaibu.monstercards;
|
||||
import android.app.Application;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||
import com.majinnaibu.monstercards.init.FlipperInitializer;
|
||||
|
||||
public class MonsterCardsApplication extends Application {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -54,15 +27,8 @@ public class MonsterCardsApplication extends Application {
|
||||
// Required initialization logic here!
|
||||
|
||||
FlipperInitializer.init(this);
|
||||
|
||||
// .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);
|
||||
AppDatabase mDB = AppDatabase.getInstance(this);
|
||||
m_monsterLibraryRepository = new MonsterRepository(mDB);
|
||||
}
|
||||
|
||||
// Called by the system when the device configuration changes while your component is running.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.majinnaibu.monstercards.data;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
||||
import com.majinnaibu.monstercards.data.enums.ArmorType;
|
||||
@@ -14,7 +12,6 @@ import com.majinnaibu.monstercards.models.Trait;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class DevContent {
|
||||
@NonNull
|
||||
public static Monster createSampleMonster() {
|
||||
Monster monster = new Monster();
|
||||
// Name
|
||||
|
||||
@@ -3,10 +3,8 @@ package com.majinnaibu.monstercards.data;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.majinnaibu.monstercards.AppDatabase;
|
||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -15,16 +13,16 @@ import io.reactivex.rxjava3.core.Completable;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public class MonsterRepository {
|
||||
|
||||
private final AppDatabase m_db;
|
||||
private AppDatabase m_db;
|
||||
|
||||
public MonsterRepository(@NonNull AppDatabase db) {
|
||||
m_db = db;
|
||||
}
|
||||
|
||||
public Flowable<List<Monster>> getMonsters() {
|
||||
|
||||
return m_db.monsterDAO()
|
||||
.getAll()
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -33,21 +31,12 @@ public class MonsterRepository {
|
||||
|
||||
public Flowable<List<Monster>> searchMonsters(String searchText) {
|
||||
return m_db.monsterDAO()
|
||||
.getAll()
|
||||
.map(monsters -> {
|
||||
ArrayList<Monster> filteredMonsters = new ArrayList<>();
|
||||
for (Monster monster : monsters) {
|
||||
if (Helpers.monsterMatchesSearch(monster, searchText)) {
|
||||
filteredMonsters.add(monster);
|
||||
}
|
||||
}
|
||||
return (List<Monster>) filteredMonsters;
|
||||
})
|
||||
.search(searchText)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public Flowable<Monster> getMonster(@NonNull UUID monsterId) {
|
||||
public Flowable<Monster> getMonster(UUID monsterId) {
|
||||
return m_db.monsterDAO()
|
||||
.loadAllByIds(new String[]{monsterId.toString()})
|
||||
.map(
|
||||
@@ -79,34 +68,4 @@ public class MonsterRepository {
|
||||
result.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class Helpers {
|
||||
static boolean monsterMatchesSearch(Monster monster, String searchText) {
|
||||
if (StringHelper.isNullOrEmpty(searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.name, searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.size, searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.type, searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.subtype, searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.alignment, searchText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.majinnaibu.monstercards.data.converters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import com.majinnaibu.monstercards.data.enums.ArmorType;
|
||||
@@ -8,7 +7,7 @@ import com.majinnaibu.monstercards.data.enums.ArmorType;
|
||||
public class ArmorTypeConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String fromArmorType(@NonNull ArmorType armorType) {
|
||||
public static String fromArmorType(ArmorType armorType) {
|
||||
return armorType.stringValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.majinnaibu.monstercards.data.converters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
||||
@@ -8,7 +7,7 @@ import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
||||
public class ChallengeRatingConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String fromChallengeRating(@NonNull ChallengeRating challengeRating) {
|
||||
public static String fromChallengeRating(ChallengeRating challengeRating) {
|
||||
return challengeRating.stringValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.majinnaibu.monstercards.data.converters;
|
||||
|
||||
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.majinnaibu.monstercards.models.SavingThrow;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SetOfSavingThrowConverter {
|
||||
|
||||
@TypeConverter
|
||||
public static String fromSetOfSavingThrow(Set<SavingThrow> savingThrows) {
|
||||
Gson gson = new Gson();
|
||||
SavingThrow[] saves = new SavingThrow[savingThrows.size()];
|
||||
savingThrows.toArray(saves);
|
||||
return gson.toJson(saves);
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static Set<SavingThrow> setOfSavingThrowFromString(String string) {
|
||||
Gson gson = new Gson();
|
||||
Type setType = new TypeToken<HashSet<SavingThrow>>() {
|
||||
}.getType();
|
||||
return gson.fromJson(string, setType);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package com.majinnaibu.monstercards.data.converters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.TypeConverter;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDConverter {
|
||||
|
||||
@NonNull
|
||||
@TypeConverter
|
||||
public static String fromUUID(@NonNull UUID uuid) {
|
||||
public static String fromUUID(UUID uuid) {
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ public enum AbilityScore {
|
||||
STRENGTH("strength", "Strength", "STR"),
|
||||
DEXTERITY("dexterity", "Dexterity", "DEX"),
|
||||
CONSTITUTION("constitution", "Constitution", "CON"),
|
||||
INTELLIGENCE("intelligence", "Intelligence", "INT"),
|
||||
INTELLIGENCE("intellligence", "Intelligence", "INT"),
|
||||
WISDOM("wisdom", "Wisdom", "WIS"),
|
||||
CHARISMA("charisma", "Charisma", "CHA"),
|
||||
;
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.majinnaibu.monstercards.data.enums;
|
||||
public enum ProficiencyType {
|
||||
NONE("none", "None", ""),
|
||||
PROFICIENT("proficient", "Proficient", "P"),
|
||||
EXPERTISE("expertise", "Expertise", "Ex"),
|
||||
EXPERTISE("experties", "Expertise", "Ex"),
|
||||
;
|
||||
|
||||
public final String displayName;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.majinnaibu.monstercards.helpers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class ArrayHelper {
|
||||
public static int indexOf(@NonNull Object[] array, Object target) {
|
||||
public static int indexOf(Object[] array, Object target) {
|
||||
for (int index = 0; index < array.length; index++) {
|
||||
if (Objects.equals(array[index], target)) {
|
||||
return index;
|
||||
|
||||
@@ -4,9 +4,20 @@ import org.commonmark.node.Document;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.Paragraph;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.NodeRenderer;
|
||||
import org.commonmark.renderer.html.HtmlNodeRendererContext;
|
||||
import org.commonmark.renderer.html.HtmlNodeRendererFactory;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
|
||||
public final class CommonMarkHelper {
|
||||
private static final class MyNodeRendererFactory implements HtmlNodeRendererFactory {
|
||||
|
||||
@Override
|
||||
public NodeRenderer create(HtmlNodeRendererContext context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toHtml(String rawCommonMark) {
|
||||
Parser parser = Parser.builder().build();
|
||||
Node document = parser.parse(rawCommonMark);
|
||||
@@ -15,7 +26,7 @@ public final class CommonMarkHelper {
|
||||
if (parent1 == parent2 && parent1 instanceof Paragraph) {
|
||||
document = new Document();
|
||||
Node child = parent1.getFirstChild();
|
||||
while (child != null) {
|
||||
while(child != null) {
|
||||
Node nextChild = child.getNext();
|
||||
document.appendChild(child);
|
||||
child = nextChild;//child.getNext();
|
||||
|
||||
@@ -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<Trait> getListOfTraits(@NonNull JsonObject dict, String name) {
|
||||
@NotNull
|
||||
public static List<Trait> getListOfTraits(@NotNull JsonObject dict, String name) {
|
||||
ArrayList<Trait> 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<Skill> getSetOfSkills(@NonNull JsonObject root) {
|
||||
public static Set<Skill> getSetOfSkills(JsonObject root) {
|
||||
HashSet<Skill> 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<String> getSetOfDamageTypes(JsonObject rootDict, String name) {
|
||||
return getSetOfDamageTypes(rootDict, name, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Set<String> getSetOfDamageTypes(@NonNull JsonObject root, String name, String type) {
|
||||
public static Set<String> getSetOfDamageTypes(JsonObject root, String name, String type) {
|
||||
HashSet<String> 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<Language> getSetOfLanguages(@NonNull JsonObject root, String name) {
|
||||
public static Set<Language> getSetOfLanguages(JsonObject root, String name) {
|
||||
HashSet<Language> languages = new HashSet<>();
|
||||
if (root.has(name)) {
|
||||
JsonElement arrayElement = root.get(name);
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
package com.majinnaibu.monstercards.helpers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@SuppressWarnings({"RedundantIfStatement"})
|
||||
@SuppressWarnings({"BooleanMethodIsAlwaysInverted", "RedundantIfStatement"})
|
||||
public final class StringHelper {
|
||||
public static boolean isNullOrEmpty(CharSequence value) {
|
||||
if (value == null) {
|
||||
@@ -18,62 +13,4 @@ public final class StringHelper {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String join(String delimiter, @NonNull Collection<String> strings) {
|
||||
int length = strings.size();
|
||||
if (length < 1) {
|
||||
return "";
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean isFirst = true;
|
||||
for (String element : strings) {
|
||||
if (!isFirst) {
|
||||
sb.append(delimiter);
|
||||
}
|
||||
|
||||
sb.append(element);
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static String oxfordJoin(String delimiter, String lastDelimiter, String onlyDelimiter, @NonNull Collection<String> strings) {
|
||||
int length = strings.size();
|
||||
if (length < 1) {
|
||||
return "";
|
||||
} else if (length == 2) {
|
||||
return join(onlyDelimiter, strings);
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int index = 0;
|
||||
int lastIndex = length - 1;
|
||||
for (String element : strings) {
|
||||
if (index > 0 && index < lastIndex) {
|
||||
sb.append(delimiter);
|
||||
} else if (index > 0 && index >= lastIndex) {
|
||||
sb.append(lastDelimiter);
|
||||
}
|
||||
sb.append(element);
|
||||
index++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Integer parseInt(String s) {
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (NumberFormatException _ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean containsCaseInsensitive(@NonNull String text, @NonNull String search) {
|
||||
// TODO: find a locale independent way to do this
|
||||
return text.toLowerCase().contains(search.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +1,37 @@
|
||||
package com.majinnaibu.monstercards.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Language implements Comparator<Language>, Comparable<Language> {
|
||||
|
||||
private String mName;
|
||||
private boolean mSpeaks;
|
||||
|
||||
public Language(String name, boolean speaks) {
|
||||
mName = name;
|
||||
mSpeaks = speaks;
|
||||
}
|
||||
|
||||
private String mName;
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName(String value) {
|
||||
mName = value;
|
||||
}
|
||||
|
||||
private boolean mSpeaks;
|
||||
public boolean getSpeaks() {
|
||||
return mSpeaks;
|
||||
}
|
||||
|
||||
public void setSpeaks(boolean value) {
|
||||
mSpeaks = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Language o) {
|
||||
if (this.mSpeaks && !o.mSpeaks) {
|
||||
return -1;
|
||||
}
|
||||
if (!this.mSpeaks && o.mSpeaks) {
|
||||
return 1;
|
||||
}
|
||||
return this.mName.compareToIgnoreCase(o.mName);
|
||||
return this.getName().compareToIgnoreCase(o.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(@NonNull Language o1, Language o2) {
|
||||
if (o1.mSpeaks && !o2.mSpeaks) {
|
||||
return -1;
|
||||
}
|
||||
if (!o1.mSpeaks && o2.mSpeaks) {
|
||||
return 1;
|
||||
}
|
||||
return o1.mName.compareToIgnoreCase(o2.mName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Language)) {
|
||||
return false;
|
||||
}
|
||||
Language otherLanguage = (Language) obj;
|
||||
if (!Objects.equals(this.mName, otherLanguage.mName)) {
|
||||
return false;
|
||||
}
|
||||
if (this.mSpeaks != otherLanguage.mSpeaks) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
public int compare(Language o1, Language o2) {
|
||||
return o1.getName().compareToIgnoreCase(o2.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,14 @@ import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -268,6 +271,69 @@ public class Monster {
|
||||
regionalActions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static boolean areItemsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Objects.equals(oldItem.id, newItem.id);
|
||||
}
|
||||
|
||||
public static boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Objects.equals(oldItem.abilities, newItem.abilities) &&
|
||||
Objects.equals(oldItem.actions, newItem.actions) &&
|
||||
Objects.equals(oldItem.alignment, newItem.alignment) &&
|
||||
Objects.equals(oldItem.armorType, newItem.armorType) &&
|
||||
Objects.equals(oldItem.burrowSpeed, newItem.burrowSpeed) &&
|
||||
Objects.equals(oldItem.canHover, newItem.canHover) &&
|
||||
Objects.equals(oldItem.challengeRating, newItem.challengeRating) &&
|
||||
Objects.equals(oldItem.charismaSavingThrowAdvantage, newItem.charismaSavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.charismaSavingThrowProficiency, newItem.charismaSavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.charismaScore, newItem.charismaScore) &&
|
||||
Objects.equals(oldItem.climbSpeed, newItem.climbSpeed) &&
|
||||
Objects.equals(oldItem.conditionImmunities, newItem.conditionImmunities) &&
|
||||
Objects.equals(oldItem.constitutionSavingThrowAdvantage, newItem.constitutionSavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.constitutionSavingThrowProficiency, newItem.constitutionSavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.constitutionScore, newItem.constitutionScore) &&
|
||||
Objects.equals(oldItem.customChallengeRatingDescription, newItem.customChallengeRatingDescription) &&
|
||||
Objects.equals(oldItem.customHPDescription, newItem.customHPDescription) &&
|
||||
Objects.equals(oldItem.customProficiencyBonus, newItem.customProficiencyBonus) &&
|
||||
Objects.equals(oldItem.customSpeedDescription, newItem.customSpeedDescription) &&
|
||||
Objects.equals(oldItem.damageImmunities, newItem.damageImmunities) &&
|
||||
Objects.equals(oldItem.damageResistances, newItem.damageResistances) &&
|
||||
Objects.equals(oldItem.damageVulnerabilities, newItem.damageVulnerabilities) &&
|
||||
Objects.equals(oldItem.dexteritySavingThrowAdvantage, newItem.dexteritySavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.dexteritySavingThrowProficiency, newItem.dexteritySavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.dexterityScore, newItem.dexterityScore) &&
|
||||
Objects.equals(oldItem.flySpeed, newItem.flySpeed) &&
|
||||
Objects.equals(oldItem.hasCustomHP, newItem.hasCustomHP) &&
|
||||
Objects.equals(oldItem.hasCustomSpeed, newItem.hasCustomSpeed) &&
|
||||
Objects.equals(oldItem.hitDice, newItem.hitDice) &&
|
||||
Objects.equals(oldItem.intelligenceSavingThrowAdvantage, newItem.intelligenceSavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.intelligenceSavingThrowProficiency, newItem.intelligenceSavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.intelligenceScore, newItem.intelligenceScore) &&
|
||||
Objects.equals(oldItem.lairActions, newItem.lairActions) &&
|
||||
Objects.equals(oldItem.languages, newItem.languages) &&
|
||||
Objects.equals(oldItem.legendaryActions, newItem.legendaryActions) &&
|
||||
Objects.equals(oldItem.name, newItem.name) &&
|
||||
Objects.equals(oldItem.naturalArmorBonus, newItem.naturalArmorBonus) &&
|
||||
Objects.equals(oldItem.otherArmorDescription, newItem.otherArmorDescription) &&
|
||||
Objects.equals(oldItem.reactions, newItem.reactions) &&
|
||||
Objects.equals(oldItem.regionalActions, newItem.regionalActions) &&
|
||||
Objects.equals(oldItem.senses, newItem.senses) &&
|
||||
Objects.equals(oldItem.shieldBonus, newItem.shieldBonus) &&
|
||||
Objects.equals(oldItem.size, newItem.size) &&
|
||||
Objects.equals(oldItem.skills, newItem.skills) &&
|
||||
Objects.equals(oldItem.strengthSavingThrowAdvantage, newItem.strengthSavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.strengthSavingThrowProficiency, newItem.strengthSavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.strengthScore, newItem.strengthScore) &&
|
||||
Objects.equals(oldItem.subtype, newItem.subtype) &&
|
||||
Objects.equals(oldItem.swimSpeed, newItem.swimSpeed) &&
|
||||
Objects.equals(oldItem.telepathyRange, newItem.telepathyRange) &&
|
||||
Objects.equals(oldItem.type, newItem.type) &&
|
||||
Objects.equals(oldItem.understandsButDescription, newItem.understandsButDescription) &&
|
||||
Objects.equals(oldItem.wisdomSavingThrowAdvantage, newItem.wisdomSavingThrowAdvantage) &&
|
||||
Objects.equals(oldItem.wisdomSavingThrowProficiency, newItem.wisdomSavingThrowProficiency) &&
|
||||
Objects.equals(oldItem.wisdomScore, newItem.wisdomScore) &&
|
||||
Objects.equals(oldItem.walkSpeed, newItem.walkSpeed);
|
||||
}
|
||||
|
||||
public String getMeta() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean isFirstOutput = true;
|
||||
@@ -304,7 +370,7 @@ public class Monster {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public int getAbilityScore(@NonNull AbilityScore abilityScore) {
|
||||
public int getAbilityScore(@NotNull AbilityScore abilityScore) {
|
||||
switch (abilityScore) {
|
||||
case STRENGTH:
|
||||
return strengthScore;
|
||||
@@ -323,7 +389,7 @@ public class Monster {
|
||||
}
|
||||
}
|
||||
|
||||
public int getAbilityModifier(@NonNull AbilityScore abilityScore) {
|
||||
public int getAbilityModifier(@NotNull AbilityScore abilityScore) {
|
||||
switch (abilityScore) {
|
||||
case STRENGTH:
|
||||
return getStrengthModifier();
|
||||
@@ -342,7 +408,7 @@ public class Monster {
|
||||
}
|
||||
}
|
||||
|
||||
public AdvantageType getSavingThrowAdvantageType(@NonNull AbilityScore abilityScore) {
|
||||
public AdvantageType getSavingThrowAdvantageType(@NotNull AbilityScore abilityScore) {
|
||||
switch (abilityScore) {
|
||||
case STRENGTH:
|
||||
return strengthSavingThrowAdvantage;
|
||||
@@ -361,7 +427,7 @@ public class Monster {
|
||||
}
|
||||
}
|
||||
|
||||
public ProficiencyType getSavingThrowProficiencyType(@NonNull AbilityScore abilityScore) {
|
||||
public ProficiencyType getSavingThrowProficiencyType(@NotNull AbilityScore abilityScore) {
|
||||
switch (abilityScore) {
|
||||
case STRENGTH:
|
||||
return strengthSavingThrowProficiency;
|
||||
@@ -607,7 +673,7 @@ public class Monster {
|
||||
}
|
||||
}
|
||||
|
||||
public int getProficiencyBonus(@NonNull ProficiencyType proficiencyType) {
|
||||
public int getProficiencyBonus(@NotNull ProficiencyType proficiencyType) {
|
||||
switch (proficiencyType) {
|
||||
case PROFICIENT:
|
||||
return getProficiencyBonus();
|
||||
@@ -751,7 +817,7 @@ public class Monster {
|
||||
return abilityDescriptions;
|
||||
}
|
||||
|
||||
public String getPlaceholderReplacedText(@NonNull String rawText) {
|
||||
public String getPlaceholderReplacedText(@NotNull String rawText) {
|
||||
return rawText
|
||||
.replaceAll("\\[STR SAVE]", String.format("%+d", getSpellSaveDC(AbilityScore.STRENGTH)))
|
||||
.replaceAll("\\[STR ATK]", String.format("%+d", getAttackBonus(AbilityScore.STRENGTH)))
|
||||
@@ -816,7 +882,7 @@ public class Monster {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,11 @@ package com.majinnaibu.monstercards.models;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public class Skill implements Comparator<Skill>, Comparable<Skill> {
|
||||
@@ -52,7 +49,7 @@ public class Skill implements Comparator<Skill>, Comparable<Skill> {
|
||||
|
||||
return String.format(
|
||||
"%s%s %+d%s",
|
||||
name.charAt(0),
|
||||
name.substring(0, 1),
|
||||
name.substring(1),
|
||||
bonus,
|
||||
advantageType == AdvantageType.ADVANTAGE ? " A" : advantageType == AdvantageType.DISADVANTAGE ? " D" : ""
|
||||
@@ -69,27 +66,4 @@ public class Skill implements Comparator<Skill>, Comparable<Skill> {
|
||||
return o1.name.compareToIgnoreCase(o2.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Skill)) {
|
||||
return false;
|
||||
}
|
||||
Skill otherSkill = (Skill) obj;
|
||||
if (!Objects.equals(this.name, otherSkill.name)) {
|
||||
return false;
|
||||
}
|
||||
if (this.abilityScore != otherSkill.abilityScore) {
|
||||
return false;
|
||||
}
|
||||
if (this.advantageType != otherSkill.advantageType) {
|
||||
return false;
|
||||
}
|
||||
if (this.proficiencyType != otherSkill.proficiencyType) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
package com.majinnaibu.monstercards.models;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Trait implements Comparator<Trait>, Comparable<Trait> {
|
||||
public class Trait {
|
||||
|
||||
public String name;
|
||||
public String description;
|
||||
@@ -14,36 +9,4 @@ public class Trait implements Comparator<Trait>, Comparable<Trait> {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Trait o) {
|
||||
return compare(this, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Trait o1, Trait o2) {
|
||||
int result = o1.name.compareToIgnoreCase(o2.name);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return o1.description.compareToIgnoreCase(o2.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Trait)) {
|
||||
return false;
|
||||
}
|
||||
Trait otherTrait = (Trait) obj;
|
||||
if (!Objects.equals(this.name, otherTrait.name)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.description, otherTrait.description)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.majinnaibu.monstercards.placeholder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class for providing sample content for user interfaces created by
|
||||
* Android template wizards.
|
||||
* <p>
|
||||
* TODO: Replace all uses of this class before publishing your app.
|
||||
*/
|
||||
public class PlaceholderContent {
|
||||
|
||||
/**
|
||||
* An array of sample (placeholder) items.
|
||||
*/
|
||||
public static final List<PlaceholderItem> ITEMS = new ArrayList<PlaceholderItem>();
|
||||
|
||||
/**
|
||||
* A map of sample (placeholder) items, by ID.
|
||||
*/
|
||||
public static final Map<String, PlaceholderItem> ITEM_MAP = new HashMap<String, PlaceholderItem>();
|
||||
|
||||
private static final int COUNT = 25;
|
||||
|
||||
static {
|
||||
// Add some sample items.
|
||||
for (int i = 1; i <= COUNT; i++) {
|
||||
addItem(createPlaceholderItem(i));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addItem(PlaceholderItem item) {
|
||||
ITEMS.add(item);
|
||||
ITEM_MAP.put(item.id, item);
|
||||
}
|
||||
|
||||
private static PlaceholderItem createPlaceholderItem(int position) {
|
||||
return new PlaceholderItem(String.valueOf(position), "Item " + position, makeDetails(position));
|
||||
}
|
||||
|
||||
private static String makeDetails(int position) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Details about Item: ").append(position);
|
||||
for (int i = 0; i < position; i++) {
|
||||
builder.append("\nMore details information here.");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder item representing a piece of content.
|
||||
*/
|
||||
public static class PlaceholderItem {
|
||||
public final String id;
|
||||
public final String content;
|
||||
public final String details;
|
||||
|
||||
public PlaceholderItem(String id, String content, String details) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.majinnaibu.monstercards.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.navigation.NavDirections;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.ui.library.LibraryFragment;
|
||||
import com.majinnaibu.monstercards.ui.library.LibraryFragmentDirections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class MonsterListRecyclerViewAdapter extends RecyclerView.Adapter<MonsterListRecyclerViewAdapter.ViewHolder> {
|
||||
public interface ItemCallback {
|
||||
void onItem(Monster monster);
|
||||
}
|
||||
|
||||
// TODO: Replace SimpleItemRecyclerViewAdapter with something better like MonsterListRecyclerViewAdapter that can be reused in search
|
||||
|
||||
private final LibraryFragment mParentActivity;
|
||||
private List<Monster> mValues;
|
||||
private final boolean mTwoPane;
|
||||
private final Context mContext;
|
||||
private final ItemCallback mOnDelete;
|
||||
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Monster monster = (Monster) view.getTag();
|
||||
// TODO: I would like to call navigateToMonsterDetail(item.id) here
|
||||
if (mTwoPane) {
|
||||
// TODO: Figure out how to navigate to a MonsterDetailFragment when in two pane view.
|
||||
// Bundle arguments = new Bundle();
|
||||
// arguments.putString(ItemDetailFragment.ARG_ITEM_ID, monster.id.toString());
|
||||
// ItemDetailFragment fragment = new ItemDetailFragment();
|
||||
// fragment.setArguments(arguments);
|
||||
// mParentActivity.getSupportFragmentManager().beginTransaction()
|
||||
// .replace(R.id.item_detail_container, fragment)
|
||||
// .commit();
|
||||
} else {
|
||||
NavDirections action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monster.id.toString());
|
||||
Navigation.findNavController(view).navigate(action);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public MonsterListRecyclerViewAdapter(LibraryFragment parent,
|
||||
Flowable<List<Monster>> itemsObservable,
|
||||
ItemCallback onDelete,
|
||||
boolean twoPane) {
|
||||
mValues = new ArrayList<>();
|
||||
mParentActivity = parent;
|
||||
mTwoPane = twoPane;
|
||||
mContext = parent.getContext();
|
||||
mOnDelete = onDelete;
|
||||
|
||||
itemsObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(monsters -> {
|
||||
mValues = monsters;
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.monster_list_content, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
holder.mIdView.setText(mValues.get(position).id.toString().substring(0, 6));
|
||||
holder.mContentView.setText(mValues.get(position).name);
|
||||
|
||||
holder.itemView.setTag(mValues.get(position));
|
||||
holder.itemView.setOnClickListener(mOnClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView mIdView;
|
||||
final TextView mContentView;
|
||||
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
mIdView = view.findViewById(R.id.id_text);
|
||||
mContentView = view.findViewById(R.id.content);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteItem(int position) {
|
||||
if (mOnDelete != null) {
|
||||
Monster monster = mValues.get(position);
|
||||
mOnDelete.onItem(monster);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
@@ -21,7 +23,12 @@ public class CollectionsFragment extends MCFragment {
|
||||
collectionsViewModel = new ViewModelProvider(this).get(CollectionsViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_collections, container, false);
|
||||
final TextView textView = root.findViewById(R.id.text_collections);
|
||||
collectionsViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
|
||||
collectionsViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
|
||||
@Override
|
||||
public void onChanged(@Nullable String s) {
|
||||
textView.setText(s);
|
||||
}
|
||||
});
|
||||
return root;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import androidx.lifecycle.ViewModel;
|
||||
|
||||
public class CollectionsViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<String> mText;
|
||||
private MutableLiveData<String> mText;
|
||||
|
||||
public CollectionsViewModel() {
|
||||
mText = new MutableLiveData<>();
|
||||
|
||||
@@ -35,12 +35,11 @@ public class AbilityScorePicker extends LinearLayout {
|
||||
// TODO: use this as default but allow setting via attribute
|
||||
mLabel = "Ability Score";
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AbilityScorePicker, 0, 0);
|
||||
String label = a.getString(R.styleable.AbilityScorePicker_label);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Stepper, 0, 0);
|
||||
String label = a.getString(R.styleable.Stepper_label);
|
||||
if (label != null) {
|
||||
mLabel = label;
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View root = inflater.inflate(R.layout.component_ability_score_picker, this, true);
|
||||
@@ -70,17 +69,18 @@ public class AbilityScorePicker extends LinearLayout {
|
||||
mHolder.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
setValue((AbilityScore) parent.getItemAtPosition(position));
|
||||
mSelectedValue = (AbilityScore) parent.getItemAtPosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
setValue(mSelectedValue = AbilityScore.STRENGTH);
|
||||
mSelectedValue = AbilityScore.STRENGTH;
|
||||
}
|
||||
});
|
||||
mHolder.spinner.setSelection(ArrayHelper.indexOf(AbilityScore.values(), mSelectedValue));
|
||||
|
||||
setValue(AbilityScore.STRENGTH);
|
||||
// TODO: listen for changes on the component to update mSelectedValue;
|
||||
}
|
||||
|
||||
public AbilityScorePicker(@NonNull Context context) {
|
||||
@@ -93,8 +93,7 @@ public class AbilityScorePicker extends LinearLayout {
|
||||
|
||||
public void setValue(AbilityScore value) {
|
||||
if (value != mSelectedValue) {
|
||||
mSelectedValue = value;
|
||||
mHolder.spinner.setSelection(ArrayHelper.indexOf(AbilityScore.values(), value));
|
||||
mHolder.spinner.setSelection(ArrayHelper.indexOf(AbilityScore.values(), mSelectedValue));
|
||||
if (mOnValueChangedListener != null) {
|
||||
mOnValueChangedListener.onValueChanged(value);
|
||||
}
|
||||
@@ -125,7 +124,7 @@ public class AbilityScorePicker extends LinearLayout {
|
||||
private final Spinner spinner;
|
||||
private final TextView label;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
spinner = root.findViewById(R.id.spinner);
|
||||
label = root.findViewById(R.id.label);
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ public class AdvantagePicker extends ConstraintLayout {
|
||||
|
||||
setValue(AdvantageType.NONE);
|
||||
mHolder.group.setOnCheckedChangeListener((group, checkedId) -> {
|
||||
if (R.id.hasAdvantage == checkedId) {
|
||||
if (R.id.advantage == checkedId) {
|
||||
setValue(AdvantageType.ADVANTAGE);
|
||||
} else if (R.id.hasDisadvantage == checkedId) {
|
||||
} else if (R.id.disadvantage == checkedId) {
|
||||
setValue(AdvantageType.DISADVANTAGE);
|
||||
} else {
|
||||
setValue(AdvantageType.NONE);
|
||||
@@ -60,11 +60,11 @@ public class AdvantagePicker extends ConstraintLayout {
|
||||
}
|
||||
final int checkedId = mHolder.group.getCheckedRadioButtonId();
|
||||
if (mSelectedValue == AdvantageType.ADVANTAGE) {
|
||||
if (checkedId != R.id.hasAdvantage) {
|
||||
if (checkedId != R.id.advantage) {
|
||||
mHolder.advantage.setChecked(true);
|
||||
}
|
||||
} else if (mSelectedValue == AdvantageType.DISADVANTAGE) {
|
||||
if (checkedId != R.id.hasDisadvantage) {
|
||||
if (checkedId != R.id.disadvantage) {
|
||||
mHolder.disadvantage.setChecked(true);
|
||||
}
|
||||
} else {
|
||||
@@ -88,11 +88,11 @@ public class AdvantagePicker extends ConstraintLayout {
|
||||
final MaterialRadioButton advantage;
|
||||
final MaterialRadioButton disadvantage;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
group = root.findViewById(R.id.group);
|
||||
none = root.findViewById(R.id.hasNoAdvantage);
|
||||
advantage = root.findViewById(R.id.hasAdvantage);
|
||||
disadvantage = root.findViewById(R.id.hasDisadvantage);
|
||||
none = root.findViewById(R.id.none);
|
||||
advantage = root.findViewById(R.id.advantage);
|
||||
disadvantage = root.findViewById(R.id.disadvantage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ProficiencyPicker extends ConstraintLayout {
|
||||
final MaterialRadioButton proficient;
|
||||
final MaterialRadioButton expertise;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
group = root.findViewById(R.id.group);
|
||||
none = root.findViewById(R.id.none);
|
||||
proficient = root.findViewById(R.id.proficient);
|
||||
|
||||
@@ -13,11 +13,11 @@ import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Stepper extends ConstraintLayout {
|
||||
private final ViewHolder mHolder;
|
||||
private int mCurrentValue;
|
||||
@@ -46,7 +46,6 @@ public class Stepper extends ConstraintLayout {
|
||||
mHolder = new ViewHolder(root);
|
||||
|
||||
setValue(mCurrentValue);
|
||||
updateDisplayedValue();
|
||||
mHolder.increment.setOnClickListener(v -> setValue(mCurrentValue + mStep));
|
||||
mHolder.decrement.setOnClickListener(v -> setValue(mCurrentValue - mStep));
|
||||
|
||||
@@ -75,20 +74,17 @@ public class Stepper extends ConstraintLayout {
|
||||
public void setValue(int value) {
|
||||
int oldValue = this.mCurrentValue;
|
||||
int newValue = Math.min(mMaxValue, Math.max(mMinValue, value));
|
||||
Logger.logDebug(String.format("Setting stepper value value: %d, oldValue: %d, newValue: %d", value, oldValue, newValue));
|
||||
if (newValue != oldValue) {
|
||||
this.mCurrentValue = newValue;
|
||||
if (mOnValueChangeListener != null) {
|
||||
mOnValueChangeListener.onChange(newValue, oldValue);
|
||||
}
|
||||
updateDisplayedValue();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDisplayedValue() {
|
||||
if (mOnFormatValueCallback != null) {
|
||||
mHolder.text.setText(mOnFormatValueCallback.onFormatValue(this.mCurrentValue));
|
||||
} else {
|
||||
mHolder.text.setText(String.valueOf(this.mCurrentValue));
|
||||
if (mOnFormatValueCallback != null) {
|
||||
mHolder.text.setText(mOnFormatValueCallback.onFormatValue(this.mCurrentValue));
|
||||
} else {
|
||||
mHolder.text.setText(String.valueOf(this.mCurrentValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +94,6 @@ public class Stepper extends ConstraintLayout {
|
||||
|
||||
public void setOnFormatValueCallback(OnFormatValueCallback callback) {
|
||||
mOnFormatValueCallback = callback;
|
||||
updateDisplayedValue();
|
||||
}
|
||||
|
||||
public int getStep() {
|
||||
@@ -139,7 +134,7 @@ public class Stepper extends ConstraintLayout {
|
||||
final Button increment;
|
||||
final Button decrement;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
text = root.findViewById(R.id.text);
|
||||
label = root.findViewById(R.id.label);
|
||||
increment = root.findViewById(R.id.increment);
|
||||
|
||||
@@ -20,16 +20,13 @@ import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class DashboardFragment extends MCFragment {
|
||||
private DashboardViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
private DashboardRecyclerViewAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
mViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);
|
||||
@@ -38,18 +35,11 @@ public class DashboardFragment extends MCFragment {
|
||||
|
||||
setupRecyclerView(mHolder.list);
|
||||
|
||||
getMonsterRepository()
|
||||
.getMonsters()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(monsters -> mViewModel.setMonsters(monsters));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||
int columnCount = Math.max(1, getResources().getConfiguration().screenWidthDp / 396);
|
||||
Logger.logWTF(String.format(Locale.US, "Setting column count to %d", columnCount));
|
||||
Context context = requireContext();
|
||||
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.majinnaibu.monstercards.databinding.CardMonsterBinding;
|
||||
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.models.Trait;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.Locale;
|
||||
@@ -28,17 +29,17 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
||||
private static final DiffUtil.ItemCallback<Monster> DIFF_CALLBACK = new DiffUtil.ItemCallback<Monster>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return oldItem.id.equals(newItem.id);
|
||||
return Monster.areItemsTheSame(oldItem, newItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return oldItem.equals(newItem);
|
||||
return Monster.areContentsTheSame(oldItem, newItem);
|
||||
}
|
||||
};
|
||||
private final ItemCallback mOnClick;
|
||||
private final ItemCallback<Monster> mOnClick;
|
||||
|
||||
protected DashboardRecyclerViewAdapter(ItemCallback onClick) {
|
||||
protected DashboardRecyclerViewAdapter(ItemCallback<Monster> onClick) {
|
||||
super(DIFF_CALLBACK);
|
||||
mOnClick = onClick;
|
||||
}
|
||||
@@ -51,7 +52,6 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
Logger.logUnimplementedMethod();
|
||||
Monster monster = getItem(position);
|
||||
holder.monster = monster;
|
||||
holder.name.setText(monster.name);
|
||||
@@ -120,15 +120,11 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(holder.monster);
|
||||
mOnClick.onItem(holder.monster);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Monster monster);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final TextView name;
|
||||
public final TextView meta;
|
||||
@@ -242,7 +238,6 @@ public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, Dashboard
|
||||
|
||||
@NonNull
|
||||
public static String getChallengeRatingAbbreviation(@NonNull ChallengeRating challengeRating) {
|
||||
Logger.logUnimplementedMethod();
|
||||
switch (challengeRating) {
|
||||
case CUSTOM:
|
||||
return "*";
|
||||
|
||||
@@ -1,26 +1,50 @@
|
||||
package com.majinnaibu.monstercards.ui.dashboard;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import com.majinnaibu.monstercards.AppDatabase;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DashboardViewModel extends ViewModel {
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import io.reactivex.rxjava3.subscribers.DisposableSubscriber;
|
||||
|
||||
public class DashboardViewModel extends AndroidViewModel {
|
||||
private final AppDatabase mDB;
|
||||
private final MutableLiveData<List<Monster>> mMonsters;
|
||||
|
||||
public DashboardViewModel() {
|
||||
public DashboardViewModel(Application application) {
|
||||
super(application);
|
||||
mDB = AppDatabase.getInstance(application);
|
||||
mMonsters = new MutableLiveData<>(new ArrayList<>());
|
||||
mDB.monsterDAO()
|
||||
.getAll()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new DisposableSubscriber<List<Monster>>() {
|
||||
@Override
|
||||
public void onNext(List<Monster> monsters) {
|
||||
mMonsters.setValue(monsters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public LiveData<List<Monster>> getMonsters() {
|
||||
return mMonsters;
|
||||
}
|
||||
|
||||
public void setMonsters(List<Monster> monsters) {
|
||||
mMonsters.setValue(monsters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
@@ -15,9 +15,7 @@ import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.ui.components.Stepper;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class EditAbilityScoresFragment extends MCFragment {
|
||||
public class EditAbilityScoresFragment extends Fragment {
|
||||
private final String ABILITY_SCORE_FORMAT = "%d (%+d)";
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
@@ -27,37 +25,38 @@ public class EditAbilityScoresFragment extends MCFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_ability_scores, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_ability_scores));
|
||||
|
||||
mViewModel.getStrength().observe(getViewLifecycleOwner(), value -> mHolder.strength.setValue(value));
|
||||
mHolder.strength.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setStrength(newValue));
|
||||
mHolder.strength.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.strength.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
mViewModel.getDexterity().observe(getViewLifecycleOwner(), value -> mHolder.dexterity.setValue(value));
|
||||
mHolder.dexterity.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setDexterity(newValue));
|
||||
mHolder.dexterity.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.dexterity.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
mViewModel.getConstitution().observe(getViewLifecycleOwner(), value -> mHolder.constitution.setValue(value));
|
||||
mHolder.constitution.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setConstitution(newValue));
|
||||
mHolder.constitution.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.constitution.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
mViewModel.getIntelligence().observe(getViewLifecycleOwner(), value -> mHolder.intelligence.setValue(value));
|
||||
mHolder.intelligence.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setIntelligence(newValue));
|
||||
mHolder.intelligence.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.intelligence.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
mViewModel.getWisdom().observe(getViewLifecycleOwner(), value -> mHolder.wisdom.setValue(value));
|
||||
mHolder.wisdom.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setWisdom(newValue));
|
||||
mHolder.wisdom.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.wisdom.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
mViewModel.getCharisma().observe(getViewLifecycleOwner(), value -> mHolder.charisma.setValue(value));
|
||||
mHolder.charisma.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setCharisma(newValue));
|
||||
mHolder.charisma.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
mHolder.charisma.setOnFormatValueCallback(value -> String.format(ABILITY_SCORE_FORMAT, value, getModifier(value)));
|
||||
|
||||
return root;
|
||||
}
|
||||
@@ -70,7 +69,7 @@ public class EditAbilityScoresFragment extends MCFragment {
|
||||
final Stepper wisdom;
|
||||
final Stepper charisma;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
strength = root.findViewById(R.id.strength);
|
||||
dexterity = root.findViewById(R.id.dexterity);
|
||||
constitution = root.findViewById(R.id.constitution);
|
||||
|
||||
@@ -30,13 +30,14 @@ public class EditArmorFragment extends MCFragment {
|
||||
private ViewHolder mHolder;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_armor, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_armor));
|
||||
|
||||
mHolder.armorType.setAdapter(new ArrayAdapter<ArmorType>(requireContext(), R.layout.dropdown_list_item, ArmorType.values()) {
|
||||
@NonNull
|
||||
@@ -93,7 +94,7 @@ public class EditArmorFragment extends MCFragment {
|
||||
private final Stepper shieldBonus;
|
||||
private final EditText customArmor;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
armorType = root.findViewById(R.id.armorType);
|
||||
naturalArmorBonus = root.findViewById(R.id.naturalArmorBonus);
|
||||
hasShield = root.findViewById(R.id.hasShield);
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
@@ -29,12 +28,13 @@ public class EditBasicInfoFragment extends MCFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_basic_info, container, false);
|
||||
setTitle(getString(R.string.title_edit_basic_info));
|
||||
mHolder = new ViewHolder(root);
|
||||
|
||||
mHolder.name.setText(mViewModel.getName().getValue());
|
||||
@@ -74,7 +74,7 @@ public class EditBasicInfoFragment extends MCFragment {
|
||||
private final Stepper hitDice;
|
||||
private final SwitchMaterial hasCustomHitPoints;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
name = root.findViewById(R.id.name);
|
||||
size = root.findViewById(R.id.size);
|
||||
type = root.findViewById(R.id.type);
|
||||
|
||||
@@ -28,13 +28,14 @@ public class EditChallengeRatingFragment extends MCFragment {
|
||||
private ViewHolder mHolder;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_challenge_rating, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_challenge_rating));
|
||||
|
||||
mHolder.challengeRating.setAdapter(new ArrayAdapter<ChallengeRating>(requireContext(), R.layout.dropdown_list_item, ChallengeRating.values()) {
|
||||
@NonNull
|
||||
@@ -82,7 +83,7 @@ public class EditChallengeRatingFragment extends MCFragment {
|
||||
final EditText customChallengeRatingDescription;
|
||||
final EditText customProficiencyBonus;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
challengeRating = root.findViewById(R.id.challengeRating);
|
||||
customChallengeRatingDescription = root.findViewById(R.id.customChallengeRatingDescription);
|
||||
customProficiencyBonus = root.findViewById(R.id.customProficiencyBonus);
|
||||
|
||||
@@ -44,12 +44,13 @@ public class EditLanguageFragment extends MCFragment {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mEditMonsterViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_language, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_language));
|
||||
|
||||
mHolder.name.setText(mViewModel.getName().getValue());
|
||||
mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString())));
|
||||
@@ -80,7 +81,7 @@ public class EditLanguageFragment extends MCFragment {
|
||||
EditText name;
|
||||
SwitchCompat canSpeak;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
name = root.findViewById(R.id.name);
|
||||
canSpeak = root.findViewById(R.id.canSpeak);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.majinnaibu.monstercards.ui.editmonster;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.majinnaibu.monstercards.models.Language;
|
||||
@@ -19,7 +18,7 @@ public class EditLanguageViewModel extends ChangeTrackedViewModel {
|
||||
mLanguage = new ChangeTrackedLiveData<>(makeLanguage(), this::makeDirty);
|
||||
}
|
||||
|
||||
public void copyFromLanguage(@NonNull Language language) {
|
||||
public void copyFromLanguage(Language language) {
|
||||
mName.resetValue(language.getName());
|
||||
mCanSpeak.resetValue(language.getSpeaks());
|
||||
makeClean();
|
||||
@@ -59,7 +58,6 @@ public class EditLanguageViewModel extends ChangeTrackedViewModel {
|
||||
return getCanSpeakValue(false);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Language makeLanguage() {
|
||||
Boolean boxedValue = mCanSpeak.getValue();
|
||||
boolean canSpeak = boxedValue != null && boxedValue;
|
||||
|
||||
@@ -30,19 +30,20 @@ public class EditLanguagesFragment extends MCFragment {
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
|
||||
private void navigateToEditLanguage(@NonNull Language language) {
|
||||
private void navigateToEditLanguage(Language language) {
|
||||
NavDirections action = EditLanguagesFragmentDirections.actionEditLanguagesFragmentToEditLanguageFragment(language.getName(), language.getSpeaks());
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_languages_list, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_languages));
|
||||
setupRecyclerView(mHolder.list);
|
||||
setupAddLanguageButton(mHolder.addLanguage);
|
||||
|
||||
@@ -93,7 +94,7 @@ public class EditLanguagesFragment extends MCFragment {
|
||||
RecyclerView list;
|
||||
FloatingActionButton addLanguage;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
this.list = root.findViewById(R.id.list);
|
||||
this.addLanguage = root.findViewById(R.id.add_language);
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@ import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditLanguagesListHeaderBinding;
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditLanguagesListItemBinding;
|
||||
import com.majinnaibu.monstercards.models.Language;
|
||||
import com.majinnaibu.monstercards.ui.components.Stepper;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private final List<Language> mValues;
|
||||
private final ItemCallback mOnClick;
|
||||
private final ItemCallback<Language> mOnClick;
|
||||
private final int mTelepathyRange;
|
||||
private final String mUnderstandsBut;
|
||||
private final Stepper.OnValueChangeListener mOnTelepathyRangeChanged;
|
||||
@@ -29,7 +29,7 @@ public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<Recyc
|
||||
private final int ITEM_VIEW_TYPE = 2;
|
||||
private final String DISTANCE_IN_FEET_FORMAT = "%d ft.";
|
||||
|
||||
public EditLanguagesRecyclerViewAdapter(List<Language> items, ItemCallback onClick, int telepathyRange, Stepper.OnValueChangeListener telepathyRangeChangedListener, String understandsBut, TextWatcher understandsButChangedListener) {
|
||||
public EditLanguagesRecyclerViewAdapter(List<Language> items, ItemCallback<Language> onClick, int telepathyRange, Stepper.OnValueChangeListener telepathyRangeChangedListener, String understandsBut, TextWatcher understandsButChangedListener) {
|
||||
mValues = items;
|
||||
mOnClick = onClick;
|
||||
mTelepathyRange = telepathyRange;
|
||||
@@ -44,7 +44,7 @@ public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<Recyc
|
||||
if (viewType == HEADER_VIEW_TYPE) {
|
||||
return new HeaderViewHolder(FragmentEditLanguagesListHeaderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
return new ItemViewHolder(FragmentEditLanguagesListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
return new ItemViewHolder(com.majinnaibu.monstercards.databinding.SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +62,7 @@ public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<Recyc
|
||||
itemViewHolder.mContentView.setText(itemViewHolder.mItem.getName());
|
||||
itemViewHolder.itemView.setOnClickListener(view -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(itemViewHolder.mItem);
|
||||
mOnClick.onItem(itemViewHolder.mItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -81,10 +81,6 @@ public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<Recyc
|
||||
return ITEM_VIEW_TYPE;
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Language language);
|
||||
}
|
||||
|
||||
public static class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||
public final Stepper telepathy;
|
||||
public final EditText understandsBut;
|
||||
@@ -100,7 +96,7 @@ public class EditLanguagesRecyclerViewAdapter extends RecyclerView.Adapter<Recyc
|
||||
public final TextView mContentView;
|
||||
public Language mItem;
|
||||
|
||||
public ItemViewHolder(@NonNull FragmentEditLanguagesListItemBinding binding) {
|
||||
public ItemViewHolder(@NonNull com.majinnaibu.monstercards.databinding.SimpleListItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
mContentView = binding.content;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class EditMonsterFragment extends MCFragment {
|
||||
View root = inflater.inflate(R.layout.fragment_edit_monster, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
|
||||
setTitle(getString(R.string.title_editMonster_fmt, getString(R.string.default_monster_name)));
|
||||
setTitle(getString(R.string.title_edit_monster, getString(R.string.default_monster_name)));
|
||||
|
||||
// TODO: Show a loading spinner until we have the monster loaded.
|
||||
if (mViewModel.hasError() || !mViewModel.hasLoaded() || !Objects.equals(mViewModel.getMonsterId().getValue(), monsterId)) {
|
||||
@@ -67,7 +67,7 @@ public class EditMonsterFragment extends MCFragment {
|
||||
mViewModel.setHasLoaded(true);
|
||||
mViewModel.setHasError(false);
|
||||
mViewModel.copyFromMonster(monster);
|
||||
setTitle(getString(R.string.title_editMonster_fmt, monster.name));
|
||||
setTitle(getString(R.string.title_edit_monster, monster.name));
|
||||
dispose();
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ public class EditMonsterFragment extends MCFragment {
|
||||
TextView lairActions;
|
||||
TextView regionalActions;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
basicInfoButton = root.findViewById(R.id.basicInfo);
|
||||
armorButton = root.findViewById(R.id.armor);
|
||||
speedButton = root.findViewById(R.id.speed);
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings({"ConstantConditions"})
|
||||
@SuppressWarnings({"ConstantConditions", "unused"})
|
||||
public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
private final ChangeTrackedLiveData<UUID> mMonsterId;
|
||||
private final MutableLiveData<Boolean> mHasError;
|
||||
@@ -158,7 +158,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mRegionalActions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty);
|
||||
}
|
||||
|
||||
public void copyFromMonster(@NonNull Monster monster) {
|
||||
public void copyFromMonster(Monster monster) {
|
||||
mMonsterId.resetValue(monster.id);
|
||||
mName.resetValue(monster.name);
|
||||
mSize.resetValue(monster.size);
|
||||
@@ -206,7 +206,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mUnderstandsButDescription.resetValue(monster.understandsButDescription);
|
||||
|
||||
ArrayList<Skill> skills = new ArrayList<>(monster.skills);
|
||||
Collections.sort(skills, Skill::compareTo);
|
||||
Collections.sort(skills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name));
|
||||
mSkills.resetValue(skills);
|
||||
ArrayList<String> senses = new ArrayList<>(monster.senses);
|
||||
Collections.sort(senses, String::compareToIgnoreCase);
|
||||
@@ -224,7 +224,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
Collections.sort(conditionImmunities, String::compareToIgnoreCase);
|
||||
mConditionImmunities.resetValue(conditionImmunities);
|
||||
ArrayList<Language> languages = new ArrayList<>(monster.languages);
|
||||
Collections.sort(languages, Language::compareTo);
|
||||
Collections.sort(languages, (lang1, lang2) -> lang1.getName().compareToIgnoreCase(lang2.getName()));
|
||||
mLanguages.resetValue(languages);
|
||||
mAbilities.resetValue(new ArrayList<>(monster.abilities));
|
||||
mActions.resetValue(new ArrayList<>(monster.actions));
|
||||
@@ -247,6 +247,10 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return mMonsterId;
|
||||
}
|
||||
|
||||
public LiveData<String> getErrorMessage() {
|
||||
return mErrorMessage;
|
||||
}
|
||||
|
||||
public void setErrorMessage(@NonNull String errorMessage) {
|
||||
mErrorMessage.setValue(errorMessage);
|
||||
}
|
||||
@@ -315,22 +319,48 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mCustomHitPoints.setValue(customHitPoints);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getHitDice() {
|
||||
return mHitDice;
|
||||
}
|
||||
|
||||
public void setHitDice(int hitDice) {
|
||||
mHitDice.setValue(hitDice);
|
||||
}
|
||||
|
||||
public void setHitDice(String hitDice) {
|
||||
Integer parsedHitDice = StringHelper.parseInt(hitDice);
|
||||
this.setHitDice(parsedHitDice != null ? parsedHitDice : 0);
|
||||
}
|
||||
|
||||
public int getHitDiceUnboxed() {
|
||||
return Helpers.unboxInteger(mHitDice.getValue(), 1);
|
||||
}
|
||||
|
||||
public String getHitDiceValueAsString() {
|
||||
return mHitDice.getValue().toString();
|
||||
}
|
||||
|
||||
public LiveData<Integer> getNaturalArmorBonus() {
|
||||
return mNaturalArmorBonus;
|
||||
}
|
||||
|
||||
public void setNaturalArmorBonus(int naturalArmorBonus) {
|
||||
mNaturalArmorBonus.setValue(naturalArmorBonus);
|
||||
}
|
||||
|
||||
public void setNaturalArmorBonus(String naturalArmorBonus) {
|
||||
Integer parsedValue = StringHelper.parseInt(naturalArmorBonus);
|
||||
this.setNaturalArmorBonus(parsedValue != null ? parsedValue : 0);
|
||||
}
|
||||
|
||||
public int getNaturalArmorBonusUnboxed() {
|
||||
return Helpers.unboxInteger(mNaturalArmorBonus.getValue(), 0);
|
||||
}
|
||||
|
||||
public String getNaturalArmorBonusValueAsString() {
|
||||
return mNaturalArmorBonus.getValue().toString();
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getHasCustomHitPoints() {
|
||||
return mHasCustomHitPoints;
|
||||
}
|
||||
@@ -351,6 +381,10 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mArmorType.setValue(armorType);
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getHasShield() {
|
||||
return mHasShield;
|
||||
}
|
||||
|
||||
public void setHasShield(boolean hasShield) {
|
||||
mHasShield.setValue(hasShield);
|
||||
}
|
||||
@@ -359,10 +393,19 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return mHasShield.getValue();
|
||||
}
|
||||
|
||||
public LiveData<Integer> getShieldBonus() {
|
||||
return mShieldBonus;
|
||||
}
|
||||
|
||||
public void setShieldBonus(int shieldBonus) {
|
||||
mShieldBonus.setValue(shieldBonus);
|
||||
}
|
||||
|
||||
public void setShieldBonus(String shieldBonus) {
|
||||
Integer parsedValue = StringHelper.parseInt(shieldBonus);
|
||||
this.setShieldBonus(parsedValue != null ? parsedValue : 0);
|
||||
}
|
||||
|
||||
public int getShieldBonusUnboxed() {
|
||||
return Helpers.unboxInteger(mShieldBonus.getValue(), 0);
|
||||
}
|
||||
@@ -387,6 +430,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mWalkSpeed.setValue(walkSpeed);
|
||||
}
|
||||
|
||||
public void incrementWalkSpeed() {
|
||||
setWalkSpeed(mWalkSpeed.getValue() + 5);
|
||||
}
|
||||
|
||||
public void decrementWalkSpeed() {
|
||||
setWalkSpeed(mWalkSpeed.getValue() - 5);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getBurrowSpeed() {
|
||||
return mBurrowSpeed;
|
||||
}
|
||||
@@ -443,6 +494,38 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mCustomSpeed.setValue(customSpeed);
|
||||
}
|
||||
|
||||
public void incrementBurrowSpeed() {
|
||||
setBurrowSpeed(mBurrowSpeed.getValue() + 5);
|
||||
}
|
||||
|
||||
public void decrementBurrowSpeed() {
|
||||
setBurrowSpeed(mBurrowSpeed.getValue() - 5);
|
||||
}
|
||||
|
||||
public void incrementClimbSpeed() {
|
||||
setClimbSpeed(mClimbSpeed.getValue() + 5);
|
||||
}
|
||||
|
||||
public void decrementClimbSpeed() {
|
||||
setClimbSpeed(mClimbSpeed.getValue() - 5);
|
||||
}
|
||||
|
||||
public void incrementFlySpeed() {
|
||||
setFlySpeed(mFlySpeed.getValue() + 5);
|
||||
}
|
||||
|
||||
public void decrementFlySpeed() {
|
||||
setFlySpeed(mFlySpeed.getValue() - 5);
|
||||
}
|
||||
|
||||
public void incrementSwimSpeed() {
|
||||
setSwimSpeed(mSwimSpeed.getValue() + 5);
|
||||
}
|
||||
|
||||
public void decrementSwimSpeed() {
|
||||
setSwimSpeed(mSwimSpeed.getValue() - 5);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getStrength() {
|
||||
return mStrength;
|
||||
}
|
||||
@@ -451,6 +534,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mStrength.setValue(strength);
|
||||
}
|
||||
|
||||
public void incrementStrength() {
|
||||
setStrength(mStrength.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementStrength() {
|
||||
setStrength(mStrength.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getDexterity() {
|
||||
return mDexterity;
|
||||
}
|
||||
@@ -459,6 +550,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mDexterity.setValue(dexterity);
|
||||
}
|
||||
|
||||
public void incrementDexterity() {
|
||||
setDexterity(mDexterity.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementDexterity() {
|
||||
setDexterity(mDexterity.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getConstitution() {
|
||||
return mConstitution;
|
||||
}
|
||||
@@ -467,6 +566,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mConstitution.setValue(constitution);
|
||||
}
|
||||
|
||||
public void incrementConstitution() {
|
||||
setConstitution(mConstitution.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementConstitution() {
|
||||
setConstitution(mConstitution.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getIntelligence() {
|
||||
return mIntelligence;
|
||||
}
|
||||
@@ -475,6 +582,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mIntelligence.setValue(intelligence);
|
||||
}
|
||||
|
||||
public void incrementIntelligence() {
|
||||
setIntelligence(mIntelligence.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementIntelligence() {
|
||||
setIntelligence(mIntelligence.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getWisdom() {
|
||||
return mWisdom;
|
||||
}
|
||||
@@ -483,6 +598,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mWisdom.setValue(wisdom);
|
||||
}
|
||||
|
||||
public void incrementWisdom() {
|
||||
setWisdom(mWisdom.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementWisdom() {
|
||||
setWisdom(mWisdom.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<Integer> getCharisma() {
|
||||
return mCharisma;
|
||||
}
|
||||
@@ -491,6 +614,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
mCharisma.setValue(charisma);
|
||||
}
|
||||
|
||||
public void incrementCharisma() {
|
||||
setCharisma(mCharisma.getValue() + 1);
|
||||
}
|
||||
|
||||
public void decrementCharisma() {
|
||||
setCharisma(mCharisma.getValue() - 1);
|
||||
}
|
||||
|
||||
public LiveData<ProficiencyType> getStrengthProficiency() {
|
||||
return mStrengthProficiency;
|
||||
}
|
||||
@@ -690,6 +821,22 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return mSenses;
|
||||
}
|
||||
|
||||
public List<String> getSensesArray() {
|
||||
return mSenses.getValue();
|
||||
}
|
||||
|
||||
public String addNewSense() {
|
||||
return Helpers.addItemToList(mSenses, "", String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public void removeSense(int position) {
|
||||
Helpers.removeFromList(mSenses, position);
|
||||
}
|
||||
|
||||
public void replaceSense(String oldSense, String newSense) {
|
||||
Helpers.replaceItemInList(mSenses, oldSense, newSense, String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public LiveData<List<String>> getDamageImmunities() {
|
||||
return mDamageImmunities;
|
||||
}
|
||||
@@ -698,10 +845,78 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return mDamageImmunities.getValue();
|
||||
}
|
||||
|
||||
public String addNewDamageImmunity() {
|
||||
return Helpers.addStringToList("", mDamageImmunities);
|
||||
}
|
||||
|
||||
public void removeDamageImmunity(int position) {
|
||||
Helpers.removeFromList(mDamageImmunities, position);
|
||||
}
|
||||
|
||||
public void replaceDamageImmunity(String oldDamageType, String newDamageType) {
|
||||
Helpers.replaceItemInList(mDamageImmunities, oldDamageType, newDamageType, String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public LiveData<List<String>> getDamageResistances() {
|
||||
return mDamageResistances;
|
||||
}
|
||||
|
||||
public List<String> getDamageResistancesArray() {
|
||||
return mDamageResistances.getValue();
|
||||
}
|
||||
|
||||
public String addNewDamageResistance() {
|
||||
return Helpers.addStringToList("", mDamageResistances);
|
||||
}
|
||||
|
||||
public void removeDamageResistance(int position) {
|
||||
Helpers.removeFromList(mDamageResistances, position);
|
||||
}
|
||||
|
||||
public void replaceDamageResistance(String oldDamageType, String newDamageType) {
|
||||
Helpers.replaceItemInList(mDamageResistances, oldDamageType, newDamageType, String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public LiveData<List<String>> getDamageVulnerabilities() {
|
||||
return mDamageVulnerabilities;
|
||||
}
|
||||
|
||||
public List<String> getDamageVulnerabilitiesArray() {
|
||||
return mDamageVulnerabilities.getValue();
|
||||
}
|
||||
|
||||
public String addNewDamageVulnerability() {
|
||||
return Helpers.addStringToList("", mDamageVulnerabilities);
|
||||
}
|
||||
|
||||
public void removeDamageVulnerability(int position) {
|
||||
Helpers.removeFromList(mDamageVulnerabilities, position);
|
||||
}
|
||||
|
||||
public void replaceDamageVulnerability(String oldDamageType, String newDamageType) {
|
||||
Helpers.replaceItemInList(mDamageVulnerabilities, oldDamageType, newDamageType, String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public LiveData<List<String>> getConditionImmunities() {
|
||||
return mConditionImmunities;
|
||||
}
|
||||
|
||||
public List<String> getConditionImmunitiesArray() {
|
||||
return mConditionImmunities.getValue();
|
||||
}
|
||||
|
||||
public String addNewConditionImmunity() {
|
||||
return Helpers.addStringToList("", mConditionImmunities);
|
||||
}
|
||||
|
||||
public void removeConditionImmunity(int position) {
|
||||
Helpers.removeFromList(mConditionImmunities, position);
|
||||
}
|
||||
|
||||
public void replaceConditionImmunity(String oldDamageType, String newDamageType) {
|
||||
Helpers.replaceItemInList(mConditionImmunities, oldDamageType, newDamageType, String::compareToIgnoreCase);
|
||||
}
|
||||
|
||||
public LiveData<List<Language>> getLanguages() {
|
||||
return mLanguages;
|
||||
}
|
||||
@@ -787,7 +1002,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return monster;
|
||||
}
|
||||
|
||||
public LiveData<List<Trait>> getTraits(@NonNull TraitType type) {
|
||||
public LiveData<List<Trait>> getTraits(TraitType type) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
return mAbilities;
|
||||
@@ -807,7 +1022,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTrait(@NonNull TraitType type, int position) {
|
||||
public void removeTrait(TraitType type, int position) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
Helpers.removeFromList(mAbilities, position);
|
||||
@@ -833,7 +1048,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceTrait(@NonNull TraitType type, Trait oldTrait, Trait newTrait) {
|
||||
public void replaceTrait(TraitType type, Trait oldTrait, Trait newTrait) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
Helpers.replaceItemInList(mAbilities, oldTrait, newTrait);
|
||||
@@ -858,7 +1073,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public Trait addNewTrait(@NonNull TraitType type) {
|
||||
public Trait addNewTrait(TraitType type) {
|
||||
Trait newAction = new Trait("", "");
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
@@ -879,7 +1094,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public LiveData<List<String>> getStrings(@NonNull StringType type) {
|
||||
public LiveData<List<String>> getStrings(StringType type) {
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
return mConditionImmunities;
|
||||
@@ -897,7 +1112,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeString(@NonNull StringType type, int position) {
|
||||
public void removeString(StringType type, int position) {
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
Helpers.removeFromList(mConditionImmunities, position);
|
||||
@@ -920,7 +1135,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public String addNewString(@NonNull StringType type) {
|
||||
public String addNewString(StringType type) {
|
||||
String newString = "";
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
@@ -939,7 +1154,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void replaceString(@NonNull StringType type, String oldValue, String newValue) {
|
||||
public void replaceString(StringType type, String oldValue, String newValue) {
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
Helpers.replaceItemInList(mConditionImmunities, oldValue, newValue);
|
||||
@@ -961,7 +1176,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean moveTrait(@NonNull TraitType type, int from, int to) {
|
||||
public boolean moveTrait(TraitType type, int from, int to) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
return Helpers.moveItemInList(mAbilities, from, to);
|
||||
@@ -989,7 +1204,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return addItemToList(listData, newItem, null);
|
||||
}
|
||||
|
||||
static <T> T addItemToList(@NonNull MutableLiveData<List<T>> listData, T newItem, Comparator<? super T> comparator) {
|
||||
static <T> T addItemToList(MutableLiveData<List<T>> listData, T newItem, Comparator<? super T> comparator) {
|
||||
ArrayList<T> newList = new ArrayList<>(listData.getValue());
|
||||
newList.add(newItem);
|
||||
if (comparator != null) {
|
||||
@@ -999,14 +1214,14 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return newItem;
|
||||
}
|
||||
|
||||
static <T> void removeFromList(@NonNull MutableLiveData<List<T>> listData, int position) {
|
||||
static <T> void removeFromList(MutableLiveData<List<T>> listData, int position) {
|
||||
List<T> oldList = listData.getValue();
|
||||
ArrayList<T> newList = new ArrayList<>(oldList);
|
||||
newList.remove(position);
|
||||
listData.setValue(newList);
|
||||
}
|
||||
|
||||
static <T> void replaceItemInList(@NonNull MutableLiveData<List<T>> listData, int position, T newItem, Comparator<? super T> comparator) {
|
||||
static <T> void replaceItemInList(MutableLiveData<List<T>> listData, int position, T newItem, Comparator<? super T> comparator) {
|
||||
List<T> oldList = listData.getValue();
|
||||
if (oldList == null) {
|
||||
oldList = new ArrayList<>();
|
||||
@@ -1036,7 +1251,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
replaceItemInList(listData, position, newItem, null);
|
||||
}
|
||||
|
||||
static <T> void replaceItemInList(@NonNull MutableLiveData<List<T>> listData, T oldItem, T newItem, Comparator<? super T> comparator) {
|
||||
static <T> void replaceItemInList(MutableLiveData<List<T>> listData, T oldItem, T newItem, Comparator<? super T> comparator) {
|
||||
List<T> oldList = listData.getValue();
|
||||
if (oldList == null) {
|
||||
oldList = new ArrayList<>();
|
||||
@@ -1071,7 +1286,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
return value;
|
||||
}
|
||||
|
||||
static <T> boolean moveItemInList(@NonNull ChangeTrackedLiveData<List<T>> listData, int from, int to) {
|
||||
static <T> boolean moveItemInList(ChangeTrackedLiveData<List<T>> listData, int from, int to) {
|
||||
List<T> oldList = listData.getValue();
|
||||
if (oldList == null) {
|
||||
oldList = new ArrayList<>();
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
@@ -16,18 +16,19 @@ import com.majinnaibu.monstercards.ui.components.AdvantagePicker;
|
||||
import com.majinnaibu.monstercards.ui.components.ProficiencyPicker;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
|
||||
public class EditSavingThrowsFragment extends MCFragment {
|
||||
public class EditSavingThrowsFragment extends Fragment {
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mViewHolder;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_saving_throws, container, false);
|
||||
mViewHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_saving_throws));
|
||||
|
||||
mViewHolder.strengthProficiency.setValue(mViewModel.getStrengthProficiency().getValue());
|
||||
mViewHolder.strengthProficiency.setOnValueChangedListener(value -> mViewModel.setStrengthProficiency(value));
|
||||
@@ -76,7 +77,7 @@ public class EditSavingThrowsFragment extends MCFragment {
|
||||
AdvantagePicker charismaAdvantage;
|
||||
ProficiencyPicker charismaProficiency;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
strengthAdvantage = root.findViewById(R.id.strengthAdvantage);
|
||||
strengthProficiency = root.findViewById(R.id.strengthProficiency);
|
||||
dexterityAdvantage = root.findViewById(R.id.dexterityAdvantage);
|
||||
|
||||
@@ -51,6 +51,7 @@ public class EditSkillFragment extends MCFragment {
|
||||
mEditMonsterViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_skill, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_skill));
|
||||
|
||||
mHolder.abilityScore.setValue(mViewModel.getAbilityScore().getValue());
|
||||
mHolder.abilityScore.setOnValueChangedListener(value -> mViewModel.setAbilityScore(value));
|
||||
@@ -89,7 +90,7 @@ public class EditSkillFragment extends MCFragment {
|
||||
ProficiencyPicker proficiency;
|
||||
EditText name;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
abilityScore = root.findViewById(R.id.abilityScore);
|
||||
advantage = root.findViewById(R.id.advantage);
|
||||
proficiency = root.findViewById(R.id.proficiency);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.majinnaibu.monstercards.ui.editmonster;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
||||
@@ -22,16 +21,15 @@ public class EditSkillViewModel extends ChangeTrackedViewModel {
|
||||
mAbilityScore = new ChangeTrackedLiveData<>(AbilityScore.STRENGTH, this::makeDirty);
|
||||
mAdvantageType = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty);
|
||||
mProficiencyType = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty);
|
||||
mName = new ChangeTrackedLiveData<>("New Skill", this::makeDirty);
|
||||
mName = new ChangeTrackedLiveData<>("Unknown Skill", this::makeDirty);
|
||||
mSkill = new ChangeTrackedLiveData<>(makeSkill(), this::makeDirty);
|
||||
}
|
||||
|
||||
public void copyFromSkill(@NonNull Skill skill) {
|
||||
public void copyFromSkill(Skill skill) {
|
||||
mAbilityScore.resetValue(skill.abilityScore);
|
||||
mAdvantageType.resetValue(skill.advantageType);
|
||||
mProficiencyType.resetValue(skill.proficiencyType);
|
||||
mName.resetValue(skill.name);
|
||||
makeClean();
|
||||
}
|
||||
|
||||
public LiveData<Skill> getSkill() {
|
||||
@@ -74,7 +72,6 @@ public class EditSkillViewModel extends ChangeTrackedViewModel {
|
||||
mSkill.setValue(makeSkill());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Skill makeSkill() {
|
||||
return new Skill(mName.getValue(), mAbilityScore.getValue(), mAdvantageType.getValue(), mProficiencyType.getValue());
|
||||
}
|
||||
|
||||
@@ -31,19 +31,22 @@ public class EditSkillsFragment extends MCFragment {
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
|
||||
private void navigateToEditSkill(@NonNull Skill skill) {
|
||||
private void navigateToEditSkill(Skill skill) {
|
||||
NavDirections action = EditSkillsFragmentDirections.actionEditSkillsFragmentToEditSkillFragment(skill.name, skill.abilityScore, skill.proficiencyType, skill.advantageType);
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
View view = getView();
|
||||
assert view != null;
|
||||
Navigation.findNavController(view).navigate(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_skills_list, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_skills));
|
||||
setupRecyclerView(mHolder.list);
|
||||
setupAddSkillButton(mHolder.addSkill);
|
||||
|
||||
@@ -84,7 +87,7 @@ public class EditSkillsFragment extends MCFragment {
|
||||
RecyclerView list;
|
||||
FloatingActionButton addSkill;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
this.list = root.findViewById(R.id.list);
|
||||
this.addSkill = root.findViewById(R.id.add_skill);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditSkillsListItemBinding;
|
||||
import com.majinnaibu.monstercards.models.Skill;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -17,9 +17,9 @@ import java.util.List;
|
||||
*/
|
||||
public class EditSkillsRecyclerViewAdapter extends RecyclerView.Adapter<EditSkillsRecyclerViewAdapter.ViewHolder> {
|
||||
private final List<Skill> mValues;
|
||||
private final ItemCallback mOnClick;
|
||||
private final ItemCallback<Skill> mOnClick;
|
||||
|
||||
public EditSkillsRecyclerViewAdapter(List<Skill> items, ItemCallback onClick) {
|
||||
public EditSkillsRecyclerViewAdapter(List<Skill> items, ItemCallback<Skill> onClick) {
|
||||
mValues = items;
|
||||
mOnClick = onClick;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class EditSkillsRecyclerViewAdapter extends RecyclerView.Adapter<EditSkil
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(FragmentEditSkillsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
return new ViewHolder(com.majinnaibu.monstercards.databinding.SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,7 +36,7 @@ public class EditSkillsRecyclerViewAdapter extends RecyclerView.Adapter<EditSkil
|
||||
holder.mContentView.setText(mValues.get(position).name);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(holder.mItem);
|
||||
mOnClick.onItem(holder.mItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -46,15 +46,11 @@ public class EditSkillsRecyclerViewAdapter extends RecyclerView.Adapter<EditSkil
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Skill skill);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final TextView mContentView;
|
||||
public Skill mItem;
|
||||
|
||||
public ViewHolder(@NonNull FragmentEditSkillsListItemBinding binding) {
|
||||
public ViewHolder(@NonNull com.majinnaibu.monstercards.databinding.SimpleListItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
mContentView = binding.content;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
@@ -18,18 +18,19 @@ import com.majinnaibu.monstercards.ui.components.Stepper;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
||||
|
||||
public class EditSpeedFragment extends MCFragment {
|
||||
public class EditSpeedFragment extends Fragment {
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
View root = inflater.inflate(R.layout.fragment_edit_speed, container, false);
|
||||
mHolder = new ViewHolder(root);
|
||||
setTitle(getString(R.string.title_edit_speed));
|
||||
|
||||
mHolder.baseSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setWalkSpeed(newValue));
|
||||
mHolder.baseSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
||||
@@ -75,7 +76,7 @@ public class EditSpeedFragment extends MCFragment {
|
||||
final SwitchCompat hasCustomSpeed;
|
||||
final EditText customSpeed;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
baseSpeed = root.findViewById(R.id.baseSpeed);
|
||||
burrowSpeed = root.findViewById(R.id.burrowSpeed);
|
||||
climbSpeed = root.findViewById(R.id.climbSpeed);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class EditStringFragment extends MCFragment {
|
||||
private StringType mStringType;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
|
||||
mViewModel = new ViewModelProvider(this).get(EditStringViewModel.class);
|
||||
if (getArguments() != null) {
|
||||
EditStringFragmentArgs args = EditStringFragmentArgs.fromBundle(getArguments());
|
||||
@@ -43,6 +43,7 @@ public class EditStringFragment extends MCFragment {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
@@ -68,21 +69,20 @@ public class EditStringFragment extends MCFragment {
|
||||
return root;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getTitleForStringType(@NonNull StringType type) {
|
||||
private String getTitleForStringType(StringType type) {
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
return getString(R.string.title_editConditionImmunity);
|
||||
return getString(R.string.title_edit_condition_immunity);
|
||||
case DAMAGE_IMMUNITY:
|
||||
return getString(R.string.title_editDamageImmunity);
|
||||
return getString(R.string.title_edit_damage_immunity);
|
||||
case DAMAGE_RESISTANCE:
|
||||
return getString(R.string.title_editDamageResistance);
|
||||
return getString(R.string.title_edit_damage_resistance);
|
||||
case DAMAGE_VULNERABILITY:
|
||||
return getString(R.string.title_editDamageVulnerability);
|
||||
return getString(R.string.title_edit_damage_vulnerability);
|
||||
case SENSE:
|
||||
return getString(R.string.title_editSense);
|
||||
return getString(R.string.title_edit_sense);
|
||||
default:
|
||||
return getString(R.string.title_editString);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class EditStringFragment extends MCFragment {
|
||||
private static class ViewHolder {
|
||||
EditText description;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
description = root.findViewById(R.id.description);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java
|
||||
import androidx.fragment.app.Fragment;
|
||||
========
|
||||
import androidx.lifecycle.LiveData;
|
||||
>>>>>>>> f924bdd (Replaces condition immunities, damage immunities, damage resistances, damage vulnerabilities, and senses with a unified list of strings editor.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsFragment.java
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavBackStackEntry;
|
||||
import androidx.navigation.NavController;
|
||||
@@ -21,20 +25,39 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.majinnaibu.monstercards.R;
|
||||
<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java
|
||||
========
|
||||
import com.majinnaibu.monstercards.data.enums.StringType;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
>>>>>>>> f924bdd (Replaces condition immunities, damage immunities, damage resistances, damage vulnerabilities, and senses with a unified list of strings editor.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsFragment.java
|
||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
public class EditConditionImmunitiesFragment extends Fragment {
|
||||
========
|
||||
import java.util.List;
|
||||
|
||||
public class EditStringsFragment extends MCFragment {
|
||||
>>>>>>>> f924bdd (Replaces condition immunities, damage immunities, damage resistances, damage vulnerabilities, and senses with a unified list of strings editor.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsFragment.java
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
private StringType mStringType;
|
||||
|
||||
<<<<<<<< HEAD:Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java
|
||||
private void navigateToEditConditionImmunity(String condition) {
|
||||
NavDirections action = EditConditionImmunitiesFragmentDirections.actionEditConditionImmunitiesFragmentToEditConditionImmunity(condition);
|
||||
View view = getView();
|
||||
assert view != null;
|
||||
Navigation.findNavController(view).navigate(action);
|
||||
========
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
|
||||
Bundle arguments = getArguments();
|
||||
if (arguments != null) {
|
||||
EditStringsFragmentArgs args = EditStringsFragmentArgs.fromBundle(arguments);
|
||||
@@ -43,11 +66,13 @@ public class EditStringsFragment extends MCFragment {
|
||||
Logger.logWTF("EditStringsFragment needs arguments");
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
>>>>>>>> f924bdd (Replaces condition immunities, damage immunities, damage resistances, damage vulnerabilities, and senses with a unified list of strings editor.):Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsFragment.java
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
@@ -59,21 +84,20 @@ public class EditStringsFragment extends MCFragment {
|
||||
return root;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getTitleForStringType(StringType type) {
|
||||
switch (type) {
|
||||
case CONDITION_IMMUNITY:
|
||||
return getString(R.string.title_editConditionImmunities);
|
||||
return getString(R.string.title_edit_condition_immunities);
|
||||
case DAMAGE_IMMUNITY:
|
||||
return getString(R.string.title_editDamageImmunities);
|
||||
return getString(R.string.title_edit_damage_immunities);
|
||||
case DAMAGE_RESISTANCE:
|
||||
return getString(R.string.title_editDamageResistances);
|
||||
return getString(R.string.title_edit_damage_resistances);
|
||||
case DAMAGE_VULNERABILITY:
|
||||
return getString(R.string.title_editDamageVulnerabilities);
|
||||
return getString(R.string.title_edit_damage_vulnerabilities);
|
||||
case SENSE:
|
||||
return getString(R.string.title_editSenses);
|
||||
return getString(R.string.title_edit_senses);
|
||||
default:
|
||||
return getString(R.string.title_editStrings);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +145,7 @@ public class EditStringsFragment extends MCFragment {
|
||||
RecyclerView list;
|
||||
FloatingActionButton addItem;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
list = root.findViewById(R.id.list);
|
||||
addItem = root.findViewById(R.id.add_item);
|
||||
}
|
||||
|
||||
@@ -7,15 +7,16 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditStringsListItemBinding;
|
||||
import com.majinnaibu.monstercards.databinding.SimpleListItemBinding;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter<EditStringsRecyclerViewAdapter.ViewHolder> {
|
||||
private final List<String> mValues;
|
||||
private final ItemCallback mOnClick;
|
||||
private final ItemCallback<String> mOnClick;
|
||||
|
||||
public EditStringsRecyclerViewAdapter(List<String> items, ItemCallback onClick) {
|
||||
public EditStringsRecyclerViewAdapter(List<String> items, ItemCallback<String> onClick) {
|
||||
mValues = items;
|
||||
mOnClick = onClick;
|
||||
}
|
||||
@@ -23,7 +24,7 @@ public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter<EditStr
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(FragmentEditStringsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
return new ViewHolder(SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,7 +33,7 @@ public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter<EditStr
|
||||
holder.mContentView.setText(mValues.get(position));
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(holder.mItem);
|
||||
mOnClick.onItem(holder.mItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -42,15 +43,11 @@ public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter<EditStr
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(String value);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final TextView mContentView;
|
||||
public String mItem;
|
||||
|
||||
public ViewHolder(@NonNull FragmentEditStringsListItemBinding binding) {
|
||||
public ViewHolder(@NonNull SimpleListItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
mContentView = binding.content;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class EditTraitFragment extends MCFragment {
|
||||
private TraitType mTraitType;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
|
||||
mViewModel = new ViewModelProvider(this).get(EditTraitViewModel.class);
|
||||
if (getArguments() != null) {
|
||||
EditTraitFragmentArgs args = EditTraitFragmentArgs.fromBundle(getArguments());
|
||||
@@ -44,7 +44,7 @@ public class EditTraitFragment extends MCFragment {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
@@ -82,19 +82,19 @@ public class EditTraitFragment extends MCFragment {
|
||||
private String getTitleForTraitType(TraitType type) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
return getString(R.string.title_editAbility);
|
||||
return getString(R.string.title_edit_ability);
|
||||
case ACTION:
|
||||
return getString(R.string.title_editAction);
|
||||
return getString(R.string.title_edit_action);
|
||||
case LAIR_ACTION:
|
||||
return getString(R.string.title_editLairAction);
|
||||
return getString(R.string.title_edit_lair_action);
|
||||
case LEGENDARY_ACTION:
|
||||
return getString(R.string.title_editLegendaryAction);
|
||||
return getString(R.string.title_edit_legendary_action);
|
||||
case REACTIONS:
|
||||
return getString(R.string.title_editReaction);
|
||||
return getString(R.string.title_edit_reaction);
|
||||
case REGIONAL_ACTION:
|
||||
return getString(R.string.title_editRegionalAction);
|
||||
return getString(R.string.title_edit_regional_action);
|
||||
default:
|
||||
return getString(R.string.title_editTrait);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class EditTraitFragment extends MCFragment {
|
||||
EditText description;
|
||||
EditText name;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
description = root.findViewById(R.id.description);
|
||||
name = root.findViewById(R.id.name);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.majinnaibu.monstercards.ui.editmonster;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
@@ -50,13 +49,12 @@ public class EditTraitViewModel extends ChangeTrackedViewModel {
|
||||
return mAbility.getValue();
|
||||
}
|
||||
|
||||
public void copyFromTrait(@NonNull Trait trait) {
|
||||
public void copyFromTrait(Trait trait) {
|
||||
makeClean();
|
||||
mName.resetValue(trait.name);
|
||||
mDescription.resetValue(trait.description);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Trait makeAbility() {
|
||||
return new Trait(mName.getValue(), mDescription.getValue());
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public class EditTraitsFragment extends MCFragment {
|
||||
private TraitType mTraitType;
|
||||
private EditTraitsRecyclerViewAdapter mAdapter;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
if (getArguments() != null) {
|
||||
@@ -47,9 +46,8 @@ public class EditTraitsFragment extends MCFragment {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
|
||||
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
|
||||
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
|
||||
|
||||
@@ -9,8 +9,9 @@ import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditTraitsListItemBinding;
|
||||
import com.majinnaibu.monstercards.databinding.SimpleListItemBinding;
|
||||
import com.majinnaibu.monstercards.models.Trait;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraitsRecyclerViewAdapter.ViewHolder> {
|
||||
private static final DiffUtil.ItemCallback<Trait> DIFF_CALLBACK = new DiffUtil.ItemCallback<Trait>() {
|
||||
@@ -25,9 +26,9 @@ public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraits
|
||||
return oldItem.equals(newItem);
|
||||
}
|
||||
};
|
||||
private final ItemCallback mOnClick;
|
||||
private final ItemCallback<Trait> mOnClick;
|
||||
|
||||
protected EditTraitsRecyclerViewAdapter(ItemCallback onClick) {
|
||||
protected EditTraitsRecyclerViewAdapter(ItemCallback<Trait> onClick) {
|
||||
super(DIFF_CALLBACK);
|
||||
mOnClick = onClick;
|
||||
}
|
||||
@@ -35,7 +36,7 @@ public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraits
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(FragmentEditTraitsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
return new ViewHolder(SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,20 +45,16 @@ public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraits
|
||||
holder.mContentView.setText(holder.mItem.name);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(holder.mItem);
|
||||
mOnClick.onItem(holder.mItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Trait trait);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public final TextView mContentView;
|
||||
public Trait mItem;
|
||||
|
||||
public ViewHolder(@NonNull FragmentEditTraitsListItemBinding binding) {
|
||||
public ViewHolder(@NonNull SimpleListItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
mContentView = binding.content;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavDirections;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
@@ -18,65 +20,52 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||
import com.majinnaibu.monstercards.databinding.FragmentLibraryBinding;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.observers.DisposableCompletableObserver;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class LibraryFragment extends MCFragment {
|
||||
private LibraryViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
private LibraryRecyclerViewAdapter mAdapter;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_library, container, false);
|
||||
|
||||
FloatingActionButton fab = root.findViewById(R.id.fab);
|
||||
assert fab != null;
|
||||
setupAddMonsterButton(fab);
|
||||
|
||||
final RecyclerView recyclerView = root.findViewById(R.id.monster_list);
|
||||
assert recyclerView != null;
|
||||
setupRecyclerView(recyclerView);
|
||||
|
||||
return root;
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mViewModel = new ViewModelProvider(this).get(LibraryViewModel.class);
|
||||
FragmentLibraryBinding binding = FragmentLibraryBinding.inflate(inflater, container, false);
|
||||
mHolder = new ViewHolder(binding);
|
||||
// TODO: set the title with setTitle(...)
|
||||
setupAddMonsterButton(mHolder.addButton);
|
||||
setupMonsterList(mHolder.list);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||
private void setupMonsterList(@NonNull RecyclerView recyclerView) {
|
||||
Context context = requireContext();
|
||||
MonsterRepository repository = this.getMonsterRepository();
|
||||
|
||||
LibraryRecyclerViewAdapter adapter = new LibraryRecyclerViewAdapter(
|
||||
context,
|
||||
repository.getMonsters(),
|
||||
(monster) -> navigateToMonsterDetail(monster.id),
|
||||
(monster) -> repository
|
||||
.deleteMonster(monster)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new DisposableCompletableObserver() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
||||
Logger.logError(e);
|
||||
}
|
||||
}));
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
LiveData<List<Monster>> monsterData = mViewModel.getMonsters();
|
||||
mAdapter = new LibraryRecyclerViewAdapter(this::navigateToMonsterDetail);
|
||||
if (monsterData != null) {
|
||||
monsterData.observe(getViewLifecycleOwner(), monsters -> mAdapter.submitList(monsters));
|
||||
}
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(requireContext(), (position, direction) -> adapter.deleteItem(position), null));
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(
|
||||
requireContext(),
|
||||
(position, direction) -> mViewModel.removeMonster(position),
|
||||
null));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@@ -98,7 +87,7 @@ public class LibraryFragment extends MCFragment {
|
||||
view,
|
||||
getString(R.string.snackbar_monster_created, monster.name),
|
||||
Snackbar.LENGTH_LONG)
|
||||
.setAction("Action", (_view) -> navigateToMonsterDetail(monster.id))
|
||||
.setAction("Action", (_view) -> navigateToMonsterDetail(monster))
|
||||
.show();
|
||||
}
|
||||
|
||||
@@ -114,8 +103,22 @@ public class LibraryFragment extends MCFragment {
|
||||
});
|
||||
}
|
||||
|
||||
protected void navigateToMonsterDetail(@NonNull UUID monsterId) {
|
||||
NavDirections action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monsterId.toString());
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
protected void navigateToMonsterDetail(Monster monster) {
|
||||
if (monster != null) {
|
||||
NavDirections action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monster.id.toString());
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
} else {
|
||||
Logger.logError("Can't navigate to MonsterDetail without a monster.");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
final FloatingActionButton addButton;
|
||||
final RecyclerView list;
|
||||
|
||||
public ViewHolder(FragmentLibraryBinding binding) {
|
||||
addButton = binding.fab;
|
||||
list = binding.monsterList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +1,53 @@
|
||||
package com.majinnaibu.monstercards.ui.library;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.databinding.SimpleListItemBinding;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.ui.shared.SimpleListItemViewHolder;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
|
||||
public class LibraryRecyclerViewAdapter extends RecyclerView.Adapter<LibraryRecyclerViewAdapter.ViewHolder> {
|
||||
private final Context mContext;
|
||||
private final ItemCallback mOnDelete;
|
||||
private final ItemCallback mOnClick;
|
||||
private final Flowable<List<Monster>> mItemsObservable;
|
||||
private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
|
||||
public class LibraryRecyclerViewAdapter extends ListAdapter<Monster, SimpleListItemViewHolder<Monster>> {
|
||||
private static final DiffUtil.ItemCallback<Monster> DIFF_CALLBACK = new DiffUtil.ItemCallback<Monster>() {
|
||||
@Override
|
||||
public void onClick(@NonNull View view) {
|
||||
Monster monster = (Monster) view.getTag();
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(monster);
|
||||
}
|
||||
public boolean areItemsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Monster.areItemsTheSame(oldItem, newItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Monster.areContentsTheSame(oldItem, newItem);
|
||||
}
|
||||
};
|
||||
private List<Monster> mValues;
|
||||
private Disposable mDisposable;
|
||||
private final ItemCallback<Monster> mOnClick;
|
||||
|
||||
public LibraryRecyclerViewAdapter(Context context,
|
||||
Flowable<List<Monster>> itemsObservable,
|
||||
ItemCallback onClick,
|
||||
ItemCallback onDelete) {
|
||||
mItemsObservable = itemsObservable;
|
||||
mValues = new ArrayList<>();
|
||||
mContext = context;
|
||||
mOnDelete = onDelete;
|
||||
public LibraryRecyclerViewAdapter(ItemCallback<Monster> onClick) {
|
||||
super(DIFF_CALLBACK);
|
||||
mOnClick = onClick;
|
||||
mDisposable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.monster_list_content, parent, false);
|
||||
return new ViewHolder(view);
|
||||
public SimpleListItemViewHolder<Monster> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
SimpleListItemBinding binding = SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new SimpleListItemViewHolder<>(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final @NonNull ViewHolder holder, int position) {
|
||||
Monster monster = mValues.get(position);
|
||||
holder.mContentView.setText(monster.name);
|
||||
public void onBindViewHolder(final @NonNull SimpleListItemViewHolder<Monster> holder, int position) {
|
||||
Monster monster = getItem(position);
|
||||
holder.item = monster;
|
||||
holder.contentView.setText(monster.name);
|
||||
holder.itemView.setTag(monster);
|
||||
holder.itemView.setOnClickListener(mOnClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
// TODO: consider moving this subscription out of the adapter and make the subscriber call setItems on the adapter
|
||||
mDisposable = mItemsObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(monsters -> {
|
||||
mValues = monsters;
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView);
|
||||
mDisposable.dispose();
|
||||
}
|
||||
|
||||
public void deleteItem(int position) {
|
||||
if (mOnDelete != null) {
|
||||
Monster monster = mValues.get(position);
|
||||
mOnDelete.onItemCallback(monster);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Monster monster);
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView mContentView;
|
||||
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
mContentView = view.findViewById(R.id.content);
|
||||
}
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItem(holder.item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.majinnaibu.monstercards.ui.library;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.majinnaibu.monstercards.AppDatabase;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.annotations.NonNull;
|
||||
import io.reactivex.rxjava3.observers.DisposableCompletableObserver;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import io.reactivex.rxjava3.subscribers.DisposableSubscriber;
|
||||
|
||||
public class LibraryViewModel extends AndroidViewModel {
|
||||
private final AppDatabase mDB;
|
||||
private final MutableLiveData<List<Monster>> mMonsters;
|
||||
|
||||
public LibraryViewModel(Application application) {
|
||||
super(application);
|
||||
mDB = AppDatabase.getInstance(application);
|
||||
mMonsters = new MutableLiveData<>(new ArrayList<>());
|
||||
mDB.monsterDAO()
|
||||
.getAll()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new DisposableSubscriber<List<Monster>>() {
|
||||
@Override
|
||||
public void onNext(List<Monster> monsters) {
|
||||
mMonsters.setValue(monsters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public LiveData<List<Monster>> getMonsters() {
|
||||
return mMonsters;
|
||||
}
|
||||
|
||||
public void removeMonster(int position) {
|
||||
Monster monster = mMonsters.getValue().get(position);
|
||||
mDB.monsterDAO()
|
||||
.delete(monster)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new DisposableCompletableObserver() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ 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;
|
||||
|
||||
@@ -30,15 +29,13 @@ 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;
|
||||
|
||||
public class MonsterDetailFragment extends MCFragment {
|
||||
private ViewHolder mHolder;
|
||||
|
||||
private MonsterDetailViewModel mViewModel;
|
||||
private MonsterDetailViewModel monsterDetailViewModel;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
@@ -47,13 +44,16 @@ public class MonsterDetailFragment extends MCFragment {
|
||||
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<Monster>() {
|
||||
@Override
|
||||
public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) {
|
||||
mViewModel.setMonster(monster);
|
||||
monsterDetailViewModel.setMonster(monster);
|
||||
dispose();
|
||||
}
|
||||
|
||||
@@ -63,98 +63,177 @@ 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);
|
||||
|
||||
final TextView monsterArmorClass = root.findViewById(R.id.armor_class);
|
||||
monsterDetailViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> monsterArmorClass.setText(Html.fromHtml("<b>Armor Class</b> " + armorText)));
|
||||
|
||||
final TextView monsterHitPoints = root.findViewById(R.id.hit_points);
|
||||
monsterDetailViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> monsterHitPoints.setText(Html.fromHtml("<b>Hit Points</b> " + hitPoints)));
|
||||
|
||||
final TextView monsterSpeed = root.findViewById(R.id.speed);
|
||||
monsterDetailViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> monsterSpeed.setText(Html.fromHtml("<b>Speed</b> " + speed)));
|
||||
|
||||
final TextView monsterStrength = root.findViewById(R.id.strength);
|
||||
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);
|
||||
|
||||
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("<b>Saving Throws</b> " + savingThrows));
|
||||
});
|
||||
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));
|
||||
|
||||
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("<b>Skills</b> " + 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("<b>Damage Vulnerabilities</b> " + 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("<b>Damage Resistances</b> " + 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("<b>Damage Immunities</b> " + 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("<b>Condition Immunities</b> " + 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("<b>Senses</b> " + 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("<b>Languages</b> " + languages));
|
||||
});
|
||||
|
||||
final TextView monsterChallenge = root.findViewById(R.id.challenge);
|
||||
monsterDetailViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> monsterChallenge.setText(Html.fromHtml("<b>Challenge</b> " + 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: add lair actions, legendary actions, reactions, and regional actions
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void setupLabeledTextView(@NonNull TextView view, String text, int titleId) {
|
||||
String title = getString(titleId);
|
||||
String fullText = String.format("<b>%s</b> %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("<b>%s</b> %s", title, text));
|
||||
}
|
||||
root.setText(formatted);
|
||||
}
|
||||
|
||||
private void setupTraitList(@NonNull LinearLayout root, @NonNull List<String> traits) {
|
||||
setupTraitList(root, traits, null, null);
|
||||
}
|
||||
|
||||
private void setupTraitList(@NonNull LinearLayout root, @NonNull List<String> 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);
|
||||
@@ -164,10 +243,12 @@ public class MonsterDetailFragment extends MCFragment {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_action_edit_monster) {
|
||||
UUID monsterId = mViewModel.getId().getValue();
|
||||
UUID monsterId = monsterDetailViewModel.getId().getValue();
|
||||
if (monsterId != null) {
|
||||
NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString());
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
View view = getView();
|
||||
assert view != null;
|
||||
Navigation.findNavController(view).navigate(action);
|
||||
} else {
|
||||
Logger.logWTF("monsterId cannot be null.");
|
||||
}
|
||||
@@ -175,82 +256,4 @@ public class MonsterDetailFragment extends MCFragment {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -181,7 +180,7 @@ public class MonsterDetailViewModel extends ViewModel {
|
||||
return mMonsterId;
|
||||
}
|
||||
|
||||
public void setMonster(@NonNull Monster monster) {
|
||||
public void setMonster(Monster monster) {
|
||||
mMonster = monster;
|
||||
mAbilities.setValue(mMonster.getAbilityDescriptions());
|
||||
mActions.setValue(mMonster.getActionDescriptions());
|
||||
|
||||
@@ -88,7 +88,7 @@ public class MonsterImportFragment extends MCFragment {
|
||||
return root;
|
||||
}
|
||||
|
||||
private void setupLabeledTextView(@NonNull TextView view, String text, int titleId) {
|
||||
private void setupLabeledTextView(TextView view, String text, int titleId) {
|
||||
String title = getString(titleId);
|
||||
String fullText = String.format("<b>%s</b> %s", title, text);
|
||||
view.setText(Html.fromHtml(fullText));
|
||||
@@ -184,7 +184,7 @@ public class MonsterImportFragment extends MCFragment {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void navigateToEditMonster(@NonNull UUID monsterId) {
|
||||
private void navigateToEditMonster(UUID monsterId) {
|
||||
NavController navController = Navigation.findNavController(requireView());
|
||||
NavDirections action;
|
||||
action = MonsterImportFragmentDirections.actionMonsterImportFragmentToNavigationLibrary();
|
||||
@@ -234,7 +234,7 @@ public class MonsterImportFragment extends MCFragment {
|
||||
final TextView regionalEffects_label;
|
||||
final ImageView regionalEffects_divider;
|
||||
|
||||
ViewHolder(@NonNull View root) {
|
||||
ViewHolder(View root) {
|
||||
this.root = root;
|
||||
name = root.findViewById(R.id.name);
|
||||
meta = root.findViewById(R.id.meta);
|
||||
|
||||
@@ -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;
|
||||
@@ -184,7 +183,7 @@ public class MonsterImportViewModel extends ViewModel {
|
||||
return mMonster;
|
||||
}
|
||||
|
||||
public void setMonster(@NonNull Monster monster) {
|
||||
public void setMonster(Monster monster) {
|
||||
mMonster = monster;
|
||||
mAbilities.setValue(mMonster.getAbilityDescriptions());
|
||||
mActions.setValue(mMonster.getActionDescriptions());
|
||||
|
||||
@@ -1,34 +1,49 @@
|
||||
package com.majinnaibu.monstercards.ui.search;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.NavDirections;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||
import com.majinnaibu.monstercards.databinding.FragmentSearchBinding;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SearchFragment extends MCFragment {
|
||||
private SearchViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
private SearchResultsRecyclerViewAdapter mAdapter;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.fragment_search, container, false);
|
||||
MonsterRepository repository = this.getMonsterRepository();
|
||||
SearchResultsRecyclerViewAdapter adapter = new SearchResultsRecyclerViewAdapter(repository, null);
|
||||
final RecyclerView recyclerView = root.findViewById(R.id.monster_list);
|
||||
assert recyclerView != null;
|
||||
setupRecyclerView(recyclerView, adapter);
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mViewModel = new ViewModelProvider(this).get(SearchViewModel.class);
|
||||
FragmentSearchBinding binding = FragmentSearchBinding.inflate(inflater, container, false);
|
||||
mHolder = new ViewHolder(binding);
|
||||
// TODO: set the title with setTitle(...)
|
||||
setupMonsterList(binding.monsterList);
|
||||
setupFilterBox(binding.searchQuery);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
final TextView textView = root.findViewById(R.id.search_query);
|
||||
textView.addTextChangedListener(new TextWatcher() {
|
||||
private void setupFilterBox(@NonNull TextView textBox) {
|
||||
textBox.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
||||
}
|
||||
@@ -39,15 +54,42 @@ public class SearchFragment extends MCFragment {
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
adapter.doSearch(textView.getText().toString());
|
||||
mViewModel.setFilterText(textBox.getText().toString());
|
||||
}
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView, @NonNull SearchResultsRecyclerViewAdapter adapter) {
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
private void setupMonsterList(@NonNull RecyclerView recyclerView) {
|
||||
Context context = requireContext();
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
LiveData<List<Monster>> monsterData = mViewModel.getMatchedMonsters();
|
||||
mAdapter = new SearchResultsRecyclerViewAdapter(this::navigateToMonsterDetail);
|
||||
if (monsterData != null) {
|
||||
monsterData.observe(getViewLifecycleOwner(), monsters -> mAdapter.submitList(monsters));
|
||||
}
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
}
|
||||
|
||||
public void navigateToMonsterDetail(Monster monster) {
|
||||
if (monster == null) {
|
||||
NavDirections action = SearchFragmentDirections.actionNavigationSearchToNavigationMonster(monster.id.toString());
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
} else {
|
||||
Logger.logError("Can't navigate to MonsterDetail without a monster.");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewHolder {
|
||||
final RecyclerView monsterList;
|
||||
final EditText filterQuery;
|
||||
|
||||
public ViewHolder(FragmentSearchBinding binding) {
|
||||
monsterList = binding.monsterList;
|
||||
filterQuery = binding.searchQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,52 @@
|
||||
package com.majinnaibu.monstercards.ui.search;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
|
||||
import com.majinnaibu.monstercards.R;
|
||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
||||
import com.majinnaibu.monstercards.databinding.SimpleListItemBinding;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
import com.majinnaibu.monstercards.ui.shared.SimpleListItemViewHolder;
|
||||
import com.majinnaibu.monstercards.utils.ItemCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.core.Flowable;
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter<SearchResultsRecyclerViewAdapter.ViewHolder> {
|
||||
private final MonsterRepository mRepository;
|
||||
private final ItemCallback mOnClickHandler;
|
||||
private String mSearchText;
|
||||
private List<Monster> mValues;
|
||||
private Disposable mSubscriptionHandler;
|
||||
|
||||
public SearchResultsRecyclerViewAdapter(MonsterRepository repository,
|
||||
ItemCallback onClick) {
|
||||
mRepository = repository;
|
||||
mSearchText = "";
|
||||
mValues = new ArrayList<>();
|
||||
mOnClickHandler = onClick;
|
||||
mSubscriptionHandler = null;
|
||||
|
||||
doSearch(mSearchText);
|
||||
}
|
||||
|
||||
public void doSearch(String searchText) {
|
||||
if (mSubscriptionHandler != null && !mSubscriptionHandler.isDisposed()) {
|
||||
mSubscriptionHandler.dispose();
|
||||
public class SearchResultsRecyclerViewAdapter extends ListAdapter<Monster, SimpleListItemViewHolder<Monster>> {
|
||||
private static final DiffUtil.ItemCallback<Monster> DIFF_CALLBACK = new DiffUtil.ItemCallback<Monster>() {
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Monster.areItemsTheSame(oldItem, newItem);
|
||||
}
|
||||
mSearchText = searchText;
|
||||
Flowable<List<Monster>> foundMonsters = mRepository.searchMonsters(mSearchText);
|
||||
mSubscriptionHandler = foundMonsters.subscribe(monsters -> {
|
||||
mValues = monsters;
|
||||
notifyDataSetChanged();
|
||||
},
|
||||
throwable -> Logger.logError("Error performing search", throwable));
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
||||
return Monster.areContentsTheSame(oldItem, newItem);
|
||||
}
|
||||
};
|
||||
private final ItemCallback<Monster> mOnClick;
|
||||
|
||||
public SearchResultsRecyclerViewAdapter(ItemCallback<Monster> onClick) {
|
||||
super(DIFF_CALLBACK);
|
||||
mOnClick = onClick;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.monster_list_content, parent, false);
|
||||
return new ViewHolder(view);
|
||||
public SimpleListItemViewHolder<Monster> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
SimpleListItemBinding binding = SimpleListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new SimpleListItemViewHolder<>(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
||||
Monster monster = mValues.get(position);
|
||||
holder.mContentView.setText(monster.name);
|
||||
holder.itemView.setTag(monster);
|
||||
public void onBindViewHolder(@NonNull final SimpleListItemViewHolder<Monster> holder, int position) {
|
||||
Monster monster = getItem(position);
|
||||
holder.item = monster;
|
||||
holder.contentView.setText(monster.name);
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
if (mOnClickHandler != null) {
|
||||
mOnClickHandler.onItem(monster);
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItem(holder.item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItem(Monster monster);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final TextView mContentView;
|
||||
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
mContentView = view.findViewById(R.id.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.majinnaibu.monstercards.ui.search;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MediatorLiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.majinnaibu.monstercards.AppDatabase;
|
||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.utils.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
import io.reactivex.rxjava3.subscribers.DisposableSubscriber;
|
||||
|
||||
public class SearchViewModel extends AndroidViewModel {
|
||||
private final MutableLiveData<List<Monster>> mAllMonsters;
|
||||
private final MediatorLiveData<List<Monster>> mFilteredMonsters;
|
||||
private final MutableLiveData<String> mFilterText;
|
||||
private final AppDatabase mDB;
|
||||
|
||||
public SearchViewModel(Application application) {
|
||||
super(application);
|
||||
mDB = AppDatabase.getInstance(application);
|
||||
mAllMonsters = new MutableLiveData<>(new ArrayList<>());
|
||||
mFilterText = new MutableLiveData<>("");
|
||||
mFilteredMonsters = new MediatorLiveData<>();
|
||||
mFilteredMonsters.addSource(
|
||||
mAllMonsters,
|
||||
allMonsters -> mFilteredMonsters.setValue(
|
||||
filterMonsters(allMonsters, mFilterText.getValue())));
|
||||
mFilteredMonsters.addSource(
|
||||
mFilterText,
|
||||
filterText -> mFilteredMonsters.setValue(
|
||||
filterMonsters(mAllMonsters.getValue(), filterText)));
|
||||
mDB.monsterDAO()
|
||||
.getAll()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(new DisposableSubscriber<List<Monster>>() {
|
||||
@Override
|
||||
public void onNext(List<Monster> monsters) {
|
||||
mAllMonsters.setValue(monsters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean monsterMatchesFilter(Monster monster, String filterText) {
|
||||
if (StringHelper.isNullOrEmpty(filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.name, filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.size, filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.type, filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.subtype, filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringHelper.containsCaseInsensitive(monster.alignment, filterText)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<Monster> filterMonsters(List<Monster> allMonsters, String filterText) {
|
||||
ArrayList<Monster> filteredMonsters = new ArrayList<>();
|
||||
filterText = filterText.toLowerCase(Locale.ROOT);
|
||||
if (allMonsters != null) {
|
||||
for (Monster monster : allMonsters) {
|
||||
// TODO: do the filtering like the iOS app does.
|
||||
Logger.logUnimplementedFeature("do the filtering like the iOS app does");
|
||||
// TODO: consider splitting search text into words and if each word appears in any of these fields return true e.g, "large demon" would match large in size and demon in type.
|
||||
// TODO: add tags and search by tags
|
||||
// TODO: add a display of what fields matched on each item in the results
|
||||
// TODO: make the criteria configurable from this screen
|
||||
// TODO: find a way to add challenge rating as a search criteria
|
||||
if (monsterMatchesFilter(monster, filterText)) {
|
||||
filteredMonsters.add(monster);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredMonsters;
|
||||
}
|
||||
|
||||
public LiveData<List<Monster>> getMatchedMonsters() {
|
||||
return mFilteredMonsters;
|
||||
}
|
||||
|
||||
public void setFilterText(String filterText) {
|
||||
mFilterText.setValue(filterText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.majinnaibu.monstercards.ui.shared;
|
||||
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.SimpleListItemBinding;
|
||||
|
||||
public class SimpleListItemViewHolder<T> extends RecyclerView.ViewHolder {
|
||||
public final TextView contentView;
|
||||
public T item;
|
||||
|
||||
public SimpleListItemViewHolder(SimpleListItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
contentView = binding.content;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
||||
private final OnMoveCallback mOnMove;
|
||||
private final Context mContext;
|
||||
|
||||
public SwipeToDeleteCallback(@NonNull Context context, OnSwipeCallback onDelete, OnMoveCallback onMove) {
|
||||
public SwipeToDeleteCallback(Context context, OnSwipeCallback onDelete, OnMoveCallback onMove) {
|
||||
super(onMove == null ? 0 : ItemTouchHelper.UP | ItemTouchHelper.DOWN, onDelete == null ? 0 : ItemTouchHelper.LEFT);
|
||||
mOnDelete = onDelete;
|
||||
mOnMove = onMove;
|
||||
|
||||
@@ -4,7 +4,6 @@ import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ChangeTrackedLiveData<T> extends MutableLiveData<T> {
|
||||
private final OnValueChangedCallback<T> mOnValueChangedCallback;
|
||||
private final OnValueDirtiedCallback mOnValueDirtiedCallback;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.majinnaibu.monstercards.utils;
|
||||
|
||||
public interface ItemCallback<T> {
|
||||
void onItem(T item);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.majinnaibu.monstercards.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Logger {
|
||||
public static final String LOG_TAG = "MonsterCards";
|
||||
|
||||
@@ -38,7 +37,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.wtf(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
@@ -56,7 +55,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.e(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
@@ -74,7 +73,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.w(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
@@ -92,7 +91,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.i(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
@@ -110,7 +109,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.d(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
@@ -128,7 +127,7 @@ public class Logger {
|
||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
||||
|
||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
||||
String message = String.format("Unexpected error occurred at %s.", location);
|
||||
String message = String.format("Unexpected error occured at %s.", location);
|
||||
Log.v(LOG_TAG, message, throwable);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.majinnaibu.monstercards.utils;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class TextChangedListener implements TextWatcher {
|
||||
|
||||
private final BeforeTextChangedCallback mBeforeTextChangedCallback;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:menu="@menu/bottom_nav_menu" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
@@ -31,5 +31,4 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:navGraph="@navigation/mobile_navigation" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -10,9 +10,9 @@
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:layout_margin="2dp"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -23,9 +23,9 @@
|
||||
android:id="@+id/advantage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:layout_margin="2dp"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -35,9 +35,9 @@
|
||||
android:id="@+id/proficiency"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:layout_margin="2dp"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -48,12 +48,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_size"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="+5" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/action_card_height"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_normal"
|
||||
android:layout_marginTop="@dimen/padding_small"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
android:textSize="@dimen/action_card_name_text_size"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -25,16 +25,14 @@
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginHorizontal="@dimen/padding_normal"
|
||||
android:layout_marginBottom="@dimen/padding_normal"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="false"
|
||||
android:textSize="@dimen/action_card_description_text_size"
|
||||
android:textSize="10sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/name"
|
||||
tools:text="Melee Weapon Attack: +8 to hit, reach 10 ft., one target. Hit: 14 (2d8 + 5) bludgeoning damage." />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:text="@string/label_armorClass_icon"
|
||||
android:layout_margin="2dp"
|
||||
android:text="AC"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -24,12 +24,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_size"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="17" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -2,34 +2,33 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:text="@string/label_challengeRating_icon"
|
||||
android:layout_margin="2dp"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:text="CR" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_size"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="1/8" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:text="@string/label_hitPoints_icon"
|
||||
android:layout_margin="2dp"
|
||||
android:text="HP"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -24,12 +24,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_size"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="367" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_icon_border_padding"
|
||||
android:text="@string/label_initiative_icon"
|
||||
android:layout_margin="2dp"
|
||||
android:text="INIT"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_tiny"
|
||||
android:textSize="8sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -24,12 +24,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textSize="@dimen/text_icon_size"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="+2" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:background="@drawable/rectangle_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_name_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -23,8 +23,8 @@
|
||||
android:id="@+id/meta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_meta_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -35,8 +35,8 @@
|
||||
android:id="@+id/challengeRating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_name_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="CR 1/8" />
|
||||
@@ -45,7 +45,7 @@
|
||||
android:id="@+id/boxesRow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:layout_margin="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/meta">
|
||||
@@ -53,8 +53,8 @@
|
||||
<include
|
||||
android:id="@+id/strength"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -64,8 +64,8 @@
|
||||
<include
|
||||
android:id="@+id/dexterity"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -75,8 +75,8 @@
|
||||
<include
|
||||
android:id="@+id/constitution"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -86,8 +86,8 @@
|
||||
<include
|
||||
android:id="@+id/intelligence"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -97,8 +97,8 @@
|
||||
<include
|
||||
android:id="@+id/wisdom"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -108,8 +108,8 @@
|
||||
<include
|
||||
android:id="@+id/charisma"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -119,8 +119,8 @@
|
||||
<include
|
||||
android:id="@+id/armorClass"
|
||||
layout="@layout/card_armor_class"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -130,15 +130,15 @@
|
||||
<include
|
||||
android:id="@+id/hitPoints"
|
||||
layout="@layout/card_hit_points"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
android:layout_marginVertical="@dimen/padding_normal"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:baselineAligned="false"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -149,26 +149,24 @@
|
||||
android:id="@+id/action1"
|
||||
layout="@layout/card_action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/action_card_height"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
android:id="@+id/action2"
|
||||
layout="@layout/card_action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/action_card_height"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
android:id="@+id/action3"
|
||||
layout="@layout/card_action"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/action_card_height"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_name_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -22,8 +22,8 @@
|
||||
android:id="@+id/meta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_meta_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -34,8 +34,8 @@
|
||||
android:id="@+id/challengeRating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:textSize="@dimen/monster_card_name_text_size"
|
||||
android:layout_margin="8dp"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="CR 1/8" />
|
||||
@@ -44,7 +44,7 @@
|
||||
android:id="@+id/boxesRow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_normal"
|
||||
android:layout_margin="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -53,8 +53,8 @@
|
||||
<include
|
||||
android:id="@+id/strength"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -64,8 +64,8 @@
|
||||
<include
|
||||
android:id="@+id/dexterity"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -75,8 +75,8 @@
|
||||
<include
|
||||
android:id="@+id/constitution"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -86,8 +86,8 @@
|
||||
<include
|
||||
android:id="@+id/intelligence"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -97,8 +97,8 @@
|
||||
<include
|
||||
android:id="@+id/wisdom"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -108,8 +108,8 @@
|
||||
<include
|
||||
android:id="@+id/charisma"
|
||||
layout="@layout/card_ability_score"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -119,8 +119,8 @@
|
||||
<include
|
||||
android:id="@+id/armorClass"
|
||||
layout="@layout/card_armor_class"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
@@ -130,7 +130,7 @@
|
||||
<include
|
||||
android:id="@+id/hitPoints"
|
||||
layout="@layout/card_hit_points"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
</LinearLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
app:layout_constraintTop_toBottomOf="@id/label">
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasNoAdvantage"
|
||||
android:id="@+id/none"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
@@ -43,7 +43,7 @@
|
||||
tools:checked="true" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasAdvantage"
|
||||
android:id="@+id/advantage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
@@ -59,7 +59,7 @@
|
||||
tools:checked="false" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasDisadvantage"
|
||||
android:id="@+id/disadvantage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_small"
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
tools:context=".ui.components.AdvantagePicker">
|
||||
<!-- // TODO: style this control to look less awful by default -->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/padding_normal"
|
||||
android:layout_marginTop="@dimen/padding_small"
|
||||
android:text="@string/label_advantage"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/label">
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasNoAdvantage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/radio_button_selector"
|
||||
android:button="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:padding="8dp"
|
||||
android:text="@string/label_advantage_none"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Button"
|
||||
android:textColor="@color/radio_button_text"
|
||||
tools:checked="true" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasAdvantage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/radio_button_selector"
|
||||
android:button="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:padding="8dp"
|
||||
android:text="@string/label_advantage_advantage"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Button"
|
||||
android:textColor="@color/radio_button_text"
|
||||
tools:checked="false" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/hasDisadvantage"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/radio_button_selector"
|
||||
android:button="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:padding="8dp"
|
||||
android:text="@string/label_advantage_disadvantage"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Button"
|
||||
android:textColor="@color/radio_button_text"
|
||||
tools:checked="false" />
|
||||
</RadioGroup>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -10,10 +10,8 @@
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:divider="?android:attr/dividerVertical"
|
||||
android:dividerPadding="@dimen/text_margin"
|
||||
android:padding="@dimen/padding_normal"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
|
||||
<!-- <include-->
|
||||
<!-- layout="@layout/card_monster"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_columnWeight="1"-->
|
||||
<!-- android:layout_marginVertical="8dp"/>-->
|
||||
|
||||
<!-- <include-->
|
||||
<!-- layout="@layout/card_monster_short"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_columnWeight="1"-->
|
||||
<!-- android:layout_marginVertical="8dp"/>-->
|
||||
|
||||
<!-- <include-->
|
||||
<!-- layout="@layout/tile_monster"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_columnWeight="1"-->
|
||||
<!-- android:layout_marginVertical="8dp"/>-->
|
||||
|
||||
<!-- <include-->
|
||||
<!-- layout="@layout/tile_monster_short"-->
|
||||
<!-- android:layout_width="0dp"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_columnWeight="1"-->
|
||||
<!-- android:layout_marginVertical="8dp" />-->
|
||||
|
||||
</LinearLayout>
|
||||
@@ -17,7 +17,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/fragment_edit_languages_list_item" />
|
||||
tools:listitem="@layout/simple_list_item" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_language"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- understands but textbox -->
|
||||
|
||||
@@ -181,9 +181,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:text="@string/label_regional_effects"
|
||||
android:text="@string/label_regional_actions"
|
||||
android:textSize="@dimen/text_h4_size"
|
||||
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -167,5 +167,4 @@
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/fragment_edit_skills_list_item" />
|
||||
tools:listitem="@layout/simple_list_item" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_skill"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
</LinearLayout>
|
||||
@@ -1,22 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.google.android.material.textfield.TextInputLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
tools:context=".ui.editmonster.EditStringFragment">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin">
|
||||
android:hint="@string/label_description"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
tools:text="blinded" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/label_description"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
tools:text="blinded" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</ScrollView>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:listitem="@layout/fragment_edit_traits_list_item" />
|
||||
tools:listitem="@layout/simple_list_item" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_item"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user