Compare commits
2 Commits
beta
...
70d8ac8038
| Author | SHA1 | Date | |
|---|---|---|---|
| 70d8ac8038 | |||
| 7b995f0d7b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
._*
|
|
||||||
thumbs.db
|
|
||||||
17
Android/.gitignore
vendored
17
Android/.gitignore
vendored
@@ -1,17 +0,0 @@
|
|||||||
*.iml
|
|
||||||
.gradle
|
|
||||||
/local.properties
|
|
||||||
/.idea/caches
|
|
||||||
/.idea/libraries
|
|
||||||
/.idea/modules.xml
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/navEditor.xml
|
|
||||||
/.idea/assetWizardSettings.xml
|
|
||||||
/.idea/dictionaries
|
|
||||||
.DS_Store
|
|
||||||
/build
|
|
||||||
/captures
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx
|
|
||||||
/app/debug
|
|
||||||
/app/release
|
|
||||||
1
Android/.idea/.name
generated
1
Android/.idea/.name
generated
@@ -1 +0,0 @@
|
|||||||
MonsterCards
|
|
||||||
116
Android/.idea/codeStyles/Project.xml
generated
116
Android/.idea/codeStyles/Project.xml
generated
@@ -1,116 +0,0 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
|
||||||
<code_scheme name="Project" version="173">
|
|
||||||
<codeStyleSettings language="XML">
|
|
||||||
<indentOptions>
|
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
|
||||||
</indentOptions>
|
|
||||||
<arrangement>
|
|
||||||
<rules>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:android</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>xmlns:.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:id</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*:name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>name</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>style</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<rule>
|
|
||||||
<match>
|
|
||||||
<AND>
|
|
||||||
<NAME>.*</NAME>
|
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
|
||||||
</AND>
|
|
||||||
</match>
|
|
||||||
<order>BY_NAME</order>
|
|
||||||
</rule>
|
|
||||||
</section>
|
|
||||||
</rules>
|
|
||||||
</arrangement>
|
|
||||||
</codeStyleSettings>
|
|
||||||
</code_scheme>
|
|
||||||
</component>
|
|
||||||
6
Android/.idea/compiler.xml
generated
6
Android/.idea/compiler.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="16" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
21
Android/.idea/gradle.xml
generated
21
Android/.idea/gradle.xml
generated
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="Android Studio java home" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="FieldCanBeLocal" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
<inspection_tool class="TrivialIf" enabled="false" level="WARNING" enabled_by_default="false" />
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
||||||
30
Android/.idea/jarRepositories.xml
generated
30
Android/.idea/jarRepositories.xml
generated
@@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RemoteRepositoriesConfiguration">
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="central" />
|
|
||||||
<option name="name" value="Maven Central repository" />
|
|
||||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="jboss.community" />
|
|
||||||
<option name="name" value="JBoss Community repository" />
|
|
||||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="BintrayJCenter" />
|
|
||||||
<option name="name" value="BintrayJCenter" />
|
|
||||||
<option name="url" value="https://jcenter.bintray.com/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="Google" />
|
|
||||||
<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>
|
|
||||||
53
Android/.idea/misc.xml
generated
53
Android/.idea/misc.xml
generated
@@ -1,53 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="NullableNotNullManager">
|
|
||||||
<option name="myDefaultNullable" value="androidx.annotation.Nullable" />
|
|
||||||
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
|
|
||||||
<option name="myNullables">
|
|
||||||
<value>
|
|
||||||
<list size="14">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
|
||||||
<item index="6" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
|
||||||
<item index="7" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
|
||||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
|
||||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
|
||||||
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
|
||||||
<item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
|
|
||||||
<item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
|
|
||||||
<item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
|
|
||||||
</list>
|
|
||||||
</value>
|
|
||||||
</option>
|
|
||||||
<option name="myNotNulls">
|
|
||||||
<value>
|
|
||||||
<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" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
|
||||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
|
||||||
<item index="5" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
|
||||||
<item index="6" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
|
||||||
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
|
||||||
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
|
||||||
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
|
||||||
<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_X" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
17
Android/.idea/saveactions_settings.xml
generated
17
Android/.idea/saveactions_settings.xml
generated
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="SaveActionSettings">
|
|
||||||
<option name="actions">
|
|
||||||
<set>
|
|
||||||
<option value="activate" />
|
|
||||||
<option value="activateOnShortcut" />
|
|
||||||
<option value="activateOnBatch" />
|
|
||||||
<option value="noActionIfCompileErrors" />
|
|
||||||
<option value="organizeImports" />
|
|
||||||
<option value="reformat" />
|
|
||||||
<option value="rearrange" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
<option name="configurationPath" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
Android/.idea/vcs.xml
generated
6
Android/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
[](https://appcenter.ms)
|
|
||||||
|
|
||||||
# MonsterCards for Android
|
|
||||||
|
|
||||||
1
Android/app/.gitignore
vendored
1
Android/app/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
/build
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id 'com.android.application'
|
|
||||||
id 'androidx.navigation.safeargs'
|
|
||||||
}
|
|
||||||
|
|
||||||
Properties properties = new Properties()
|
|
||||||
def propertiesFile = project.rootProject.file('local.properties')
|
|
||||||
if (propertiesFile.exists()) {
|
|
||||||
properties.load(propertiesFile.newDataInputStream())
|
|
||||||
}
|
|
||||||
def appCenterLocalSecret = properties.getProperty('appCenter.localSecret')
|
|
||||||
def appCenterEnvSecret = System.getenv('APPCENTER_SECRET')
|
|
||||||
def appCenterSecret = appCenterLocalSecret != null ? appCenterLocalSecret : appCenterEnvSecret != null ? appCenterEnvSecret : ""
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 31
|
|
||||||
buildToolsVersion '30.0.3'
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "com.majinnaibu.monstercards"
|
|
||||||
minSdkVersion 22
|
|
||||||
targetSdkVersion 31
|
|
||||||
versionCode 1
|
|
||||||
versionName "1.0"
|
|
||||||
buildConfigField "String", "APPCENTER_SECRET", "\"${appCenterSecret}\""
|
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
|
|
||||||
javaCompileOptions {
|
|
||||||
annotationProcessorOptions {
|
|
||||||
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
// Enables code shrinking, obfuscation, and optimization for only
|
|
||||||
// your project's release build type.
|
|
||||||
minifyEnabled true
|
|
||||||
|
|
||||||
// Enables resource shrinking, which is performed by the
|
|
||||||
// Android Gradle plugin.
|
|
||||||
shrinkResources true
|
|
||||||
|
|
||||||
// Includes the default ProGuard rules files that are packaged with
|
|
||||||
// the Android Gradle plugin. To learn more, go to the section about
|
|
||||||
// R8 configuration files.
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
buildFeatures {
|
|
||||||
viewBinding true
|
|
||||||
}
|
|
||||||
lintOptions {
|
|
||||||
checkDependencies true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// Included libs
|
|
||||||
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.navigation:navigation-fragment:2.3.5"
|
|
||||||
implementation "androidx.navigation:navigation-ui:2.3.5"
|
|
||||||
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.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'
|
|
||||||
|
|
||||||
// Room DB
|
|
||||||
implementation 'io.reactivex.rxjava3:rxjava:3.1.0'
|
|
||||||
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
|
|
||||||
implementation "androidx.room:room-runtime:2.3.0"
|
|
||||||
annotationProcessor "androidx.room:room-compiler:2.3.0"
|
|
||||||
implementation "androidx.room:room-rxjava3:2.3.0"
|
|
||||||
//testImplementation "androidx.room:room-testing:2.3.0"
|
|
||||||
|
|
||||||
// AppCenter
|
|
||||||
debugImplementation 'com.microsoft.appcenter:appcenter-analytics:4.2.0'
|
|
||||||
debugImplementation 'com.microsoft.appcenter:appcenter-crashes:4.2.0'
|
|
||||||
|
|
||||||
// Flipper
|
|
||||||
debugImplementation 'com.facebook.flipper:flipper:0.102.0'
|
|
||||||
debugImplementation "com.facebook.soloader:soloader:0.10.1"
|
|
||||||
releaseImplementation 'com.facebook.flipper:flipper-noop:0.102.0'
|
|
||||||
|
|
||||||
// Other 3rd Party
|
|
||||||
implementation 'com.atlassian.commonmark:commonmark:0.17.0'
|
|
||||||
implementation 'com.google.code.gson:gson:2.8.7'
|
|
||||||
}
|
|
||||||
32
Android/app/proguard-rules.pro
vendored
32
Android/app/proguard-rules.pro
vendored
@@ -1,32 +0,0 @@
|
|||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
|
|
||||||
-keep enum com.majinnaibu.monstercards.data.enums.AbilityScore
|
|
||||||
-keep enum com.majinnaibu.monstercards.data.enums.ProficiencyType
|
|
||||||
-keep enum com.majinnaibu.monstercards.data.enums.AdvantageType
|
|
||||||
-keep enum com.majinnaibu.monstercards.data.enums.TraitType
|
|
||||||
-keep enum com.majinnaibu.monstercards.data.enums.StringType
|
|
||||||
-keepclassmembers,allowoptimization enum * {
|
|
||||||
<fields>;
|
|
||||||
public static **[] values();
|
|
||||||
public static ** valueOf(java.lang.String);
|
|
||||||
}
|
|
||||||
@@ -1,440 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 1,
|
|
||||||
"identityHash": "db1293d2f490940b55ca1f4f56b21b1a",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "Monster",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `blindsight_range` INTEGER NOT NULL DEFAULT 0, `is_blind_beyond_blindsight_range` INTEGER NOT NULL DEFAULT false, `darkvision_range` INTEGER NOT NULL DEFAULT 0, `tremorsense_range` INTEGER NOT NULL DEFAULT 0, `truesight_range` INTEGER NOT NULL DEFAULT 0, `telepathy_range` INTEGER NOT NULL DEFAULT 0, `understands_but_description` TEXT DEFAULT '', `skills` TEXT, `damage_immunities` TEXT, `damage_resistances` TEXT, `damage_vulnerabilities` TEXT, `condition_immunities` TEXT, `languages` TEXT, `abilities` TEXT, `actions` TEXT, `reactions` TEXT, `lair_actions` TEXT, `legendary_actions` TEXT, `regional_actions` TEXT, PRIMARY KEY(`id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "size",
|
|
||||||
"columnName": "size",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "type",
|
|
||||||
"columnName": "type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "subtype",
|
|
||||||
"columnName": "subtype",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "alignment",
|
|
||||||
"columnName": "alignment",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthScore",
|
|
||||||
"columnName": "strength_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowAdvantage",
|
|
||||||
"columnName": "strength_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowProficiency",
|
|
||||||
"columnName": "strength_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexterityScore",
|
|
||||||
"columnName": "dexterity_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowAdvantage",
|
|
||||||
"columnName": "dexterity_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowProficiency",
|
|
||||||
"columnName": "dexterity_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionScore",
|
|
||||||
"columnName": "constitution_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowAdvantage",
|
|
||||||
"columnName": "constitution_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowProficiency",
|
|
||||||
"columnName": "constitution_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceScore",
|
|
||||||
"columnName": "intelligence_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowAdvantage",
|
|
||||||
"columnName": "intelligence_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowProficiency",
|
|
||||||
"columnName": "intelligence_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomScore",
|
|
||||||
"columnName": "wisdom_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowAdvantage",
|
|
||||||
"columnName": "wisdom_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowProficiency",
|
|
||||||
"columnName": "wisdom_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaScore",
|
|
||||||
"columnName": "charisma_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowAdvantage",
|
|
||||||
"columnName": "charisma_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowProficiency",
|
|
||||||
"columnName": "charisma_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "armorType",
|
|
||||||
"columnName": "armor_type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "shieldBonus",
|
|
||||||
"columnName": "shield_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "naturalArmorBonus",
|
|
||||||
"columnName": "natural_armor_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "otherArmorDescription",
|
|
||||||
"columnName": "other_armor_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hitDice",
|
|
||||||
"columnName": "hit_dice",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomHP",
|
|
||||||
"columnName": "has_custom_hit_points",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customHPDescription",
|
|
||||||
"columnName": "custom_hit_points_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "walkSpeed",
|
|
||||||
"columnName": "walk_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "burrowSpeed",
|
|
||||||
"columnName": "burrow_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "climbSpeed",
|
|
||||||
"columnName": "climb_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "flySpeed",
|
|
||||||
"columnName": "fly_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "canHover",
|
|
||||||
"columnName": "can_hover",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "swimSpeed",
|
|
||||||
"columnName": "swim_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomSpeed",
|
|
||||||
"columnName": "has_custom_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customSpeedDescription",
|
|
||||||
"columnName": "custom_speed_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "challengeRating",
|
|
||||||
"columnName": "challenge_rating",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'1'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customChallengeRatingDescription",
|
|
||||||
"columnName": "custom_challenge_rating_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customProficiencyBonus",
|
|
||||||
"columnName": "custom_proficiency_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "blindsightRange",
|
|
||||||
"columnName": "blindsight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "isBlindBeyondBlindsightRange",
|
|
||||||
"columnName": "is_blind_beyond_blindsight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "darkvisionRange",
|
|
||||||
"columnName": "darkvision_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "tremorsenseRange",
|
|
||||||
"columnName": "tremorsense_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "truesightRange",
|
|
||||||
"columnName": "truesight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "telepathyRange",
|
|
||||||
"columnName": "telepathy_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "understandsButDescription",
|
|
||||||
"columnName": "understands_but_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "skills",
|
|
||||||
"columnName": "skills",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageImmunities",
|
|
||||||
"columnName": "damage_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageResistances",
|
|
||||||
"columnName": "damage_resistances",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageVulnerabilities",
|
|
||||||
"columnName": "damage_vulnerabilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "conditionImmunities",
|
|
||||||
"columnName": "condition_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "languages",
|
|
||||||
"columnName": "languages",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "abilities",
|
|
||||||
"columnName": "abilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "actions",
|
|
||||||
"columnName": "actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "reactions",
|
|
||||||
"columnName": "reactions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "lairActions",
|
|
||||||
"columnName": "lair_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "legendaryActions",
|
|
||||||
"columnName": "legendary_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "regionalActions",
|
|
||||||
"columnName": "regional_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'db1293d2f490940b55ca1f4f56b21b1a')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,499 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 2,
|
|
||||||
"identityHash": "6f1e7a2b2ab96fc4be4da1657a7a0138",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "monsters",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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, `blindsight_range` INTEGER NOT NULL DEFAULT 0, `is_blind_beyond_blindsight_range` INTEGER NOT NULL DEFAULT false, `darkvision_range` INTEGER NOT NULL DEFAULT 0, `tremorsense_range` INTEGER NOT NULL DEFAULT 0, `truesight_range` INTEGER NOT NULL DEFAULT 0, `telepathy_range` INTEGER NOT NULL DEFAULT 0, `understands_but_description` TEXT DEFAULT '', `skills` TEXT, `damage_immunities` TEXT, `damage_resistances` TEXT, `damage_vulnerabilities` TEXT, `condition_immunities` TEXT, `languages` TEXT, `abilities` TEXT, `actions` TEXT, `reactions` TEXT, `lair_actions` TEXT, `legendary_actions` TEXT, `regional_actions` TEXT, PRIMARY KEY(`id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "size",
|
|
||||||
"columnName": "size",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "type",
|
|
||||||
"columnName": "type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "subtype",
|
|
||||||
"columnName": "subtype",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "alignment",
|
|
||||||
"columnName": "alignment",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthScore",
|
|
||||||
"columnName": "strength_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowAdvantage",
|
|
||||||
"columnName": "strength_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowProficiency",
|
|
||||||
"columnName": "strength_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexterityScore",
|
|
||||||
"columnName": "dexterity_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowAdvantage",
|
|
||||||
"columnName": "dexterity_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowProficiency",
|
|
||||||
"columnName": "dexterity_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionScore",
|
|
||||||
"columnName": "constitution_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowAdvantage",
|
|
||||||
"columnName": "constitution_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowProficiency",
|
|
||||||
"columnName": "constitution_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceScore",
|
|
||||||
"columnName": "intelligence_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowAdvantage",
|
|
||||||
"columnName": "intelligence_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowProficiency",
|
|
||||||
"columnName": "intelligence_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomScore",
|
|
||||||
"columnName": "wisdom_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowAdvantage",
|
|
||||||
"columnName": "wisdom_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowProficiency",
|
|
||||||
"columnName": "wisdom_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaScore",
|
|
||||||
"columnName": "charisma_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowAdvantage",
|
|
||||||
"columnName": "charisma_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowProficiency",
|
|
||||||
"columnName": "charisma_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "armorType",
|
|
||||||
"columnName": "armor_type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "shieldBonus",
|
|
||||||
"columnName": "shield_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "naturalArmorBonus",
|
|
||||||
"columnName": "natural_armor_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "otherArmorDescription",
|
|
||||||
"columnName": "other_armor_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hitDice",
|
|
||||||
"columnName": "hit_dice",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomHP",
|
|
||||||
"columnName": "has_custom_hit_points",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customHPDescription",
|
|
||||||
"columnName": "custom_hit_points_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "walkSpeed",
|
|
||||||
"columnName": "walk_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "burrowSpeed",
|
|
||||||
"columnName": "burrow_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "climbSpeed",
|
|
||||||
"columnName": "climb_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "flySpeed",
|
|
||||||
"columnName": "fly_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "canHover",
|
|
||||||
"columnName": "can_hover",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "swimSpeed",
|
|
||||||
"columnName": "swim_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomSpeed",
|
|
||||||
"columnName": "has_custom_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customSpeedDescription",
|
|
||||||
"columnName": "custom_speed_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "challengeRating",
|
|
||||||
"columnName": "challenge_rating",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'1'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customChallengeRatingDescription",
|
|
||||||
"columnName": "custom_challenge_rating_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customProficiencyBonus",
|
|
||||||
"columnName": "custom_proficiency_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "blindsightRange",
|
|
||||||
"columnName": "blindsight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "isBlindBeyondBlindsightRange",
|
|
||||||
"columnName": "is_blind_beyond_blindsight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "darkvisionRange",
|
|
||||||
"columnName": "darkvision_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "tremorsenseRange",
|
|
||||||
"columnName": "tremorsense_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "truesightRange",
|
|
||||||
"columnName": "truesight_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "telepathyRange",
|
|
||||||
"columnName": "telepathy_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "understandsButDescription",
|
|
||||||
"columnName": "understands_but_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "skills",
|
|
||||||
"columnName": "skills",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageImmunities",
|
|
||||||
"columnName": "damage_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageResistances",
|
|
||||||
"columnName": "damage_resistances",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageVulnerabilities",
|
|
||||||
"columnName": "damage_vulnerabilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "conditionImmunities",
|
|
||||||
"columnName": "condition_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "languages",
|
|
||||||
"columnName": "languages",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "abilities",
|
|
||||||
"columnName": "abilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "actions",
|
|
||||||
"columnName": "actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "reactions",
|
|
||||||
"columnName": "reactions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "lairActions",
|
|
||||||
"columnName": "lair_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "legendaryActions",
|
|
||||||
"columnName": "legendary_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "regionalActions",
|
|
||||||
"columnName": "regional_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ftsVersion": "FTS4",
|
|
||||||
"ftsOptions": {
|
|
||||||
"tokenizer": "simple",
|
|
||||||
"tokenizerArgs": [],
|
|
||||||
"contentTable": "monsters",
|
|
||||||
"languageIdColumnName": "",
|
|
||||||
"matchInfo": "FTS4",
|
|
||||||
"notIndexedColumns": [],
|
|
||||||
"prefixSizes": [],
|
|
||||||
"preferredOrder": "ASC"
|
|
||||||
},
|
|
||||||
"contentSyncTriggers": [
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_BEFORE_UPDATE BEFORE UPDATE ON `monsters` BEGIN DELETE FROM `monsters_fts` WHERE `docid`=OLD.`rowid`; END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_BEFORE_DELETE BEFORE DELETE ON `monsters` BEGIN DELETE FROM `monsters_fts` WHERE `docid`=OLD.`rowid`; END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_AFTER_UPDATE AFTER UPDATE ON `monsters` BEGIN INSERT INTO `monsters_fts`(`docid`, `name`, `size`, `type`, `subtype`, `alignment`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`size`, NEW.`type`, NEW.`subtype`, NEW.`alignment`); END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_AFTER_INSERT AFTER INSERT ON `monsters` BEGIN INSERT INTO `monsters_fts`(`docid`, `name`, `size`, `type`, `subtype`, `alignment`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`size`, NEW.`type`, NEW.`subtype`, NEW.`alignment`); END"
|
|
||||||
],
|
|
||||||
"tableName": "monsters_fts",
|
|
||||||
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`name` TEXT, `size` TEXT, `type` TEXT, `subtype` TEXT, `alignment` TEXT, content=`monsters`)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "size",
|
|
||||||
"columnName": "size",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "type",
|
|
||||||
"columnName": "type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "subtype",
|
|
||||||
"columnName": "subtype",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "alignment",
|
|
||||||
"columnName": "alignment",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6f1e7a2b2ab96fc4be4da1657a7a0138')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,483 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 3,
|
|
||||||
"identityHash": "7c3c3ed79c7002102e7af7cfd21c23e0",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "monsters",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`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`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "id",
|
|
||||||
"columnName": "id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "size",
|
|
||||||
"columnName": "size",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "type",
|
|
||||||
"columnName": "type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "subtype",
|
|
||||||
"columnName": "subtype",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "alignment",
|
|
||||||
"columnName": "alignment",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthScore",
|
|
||||||
"columnName": "strength_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowAdvantage",
|
|
||||||
"columnName": "strength_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "strengthSavingThrowProficiency",
|
|
||||||
"columnName": "strength_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexterityScore",
|
|
||||||
"columnName": "dexterity_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowAdvantage",
|
|
||||||
"columnName": "dexterity_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dexteritySavingThrowProficiency",
|
|
||||||
"columnName": "dexterity_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionScore",
|
|
||||||
"columnName": "constitution_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowAdvantage",
|
|
||||||
"columnName": "constitution_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "constitutionSavingThrowProficiency",
|
|
||||||
"columnName": "constitution_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceScore",
|
|
||||||
"columnName": "intelligence_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowAdvantage",
|
|
||||||
"columnName": "intelligence_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "intelligenceSavingThrowProficiency",
|
|
||||||
"columnName": "intelligence_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomScore",
|
|
||||||
"columnName": "wisdom_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowAdvantage",
|
|
||||||
"columnName": "wisdom_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "wisdomSavingThrowProficiency",
|
|
||||||
"columnName": "wisdom_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaScore",
|
|
||||||
"columnName": "charisma_score",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowAdvantage",
|
|
||||||
"columnName": "charisma_saving_throw_advantage",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "charismaSavingThrowProficiency",
|
|
||||||
"columnName": "charisma_saving_throw_proficiency",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "armorType",
|
|
||||||
"columnName": "armor_type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'none'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "shieldBonus",
|
|
||||||
"columnName": "shield_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "naturalArmorBonus",
|
|
||||||
"columnName": "natural_armor_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "otherArmorDescription",
|
|
||||||
"columnName": "other_armor_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hitDice",
|
|
||||||
"columnName": "hit_dice",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomHP",
|
|
||||||
"columnName": "has_custom_hit_points",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customHPDescription",
|
|
||||||
"columnName": "custom_hit_points_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "walkSpeed",
|
|
||||||
"columnName": "walk_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "burrowSpeed",
|
|
||||||
"columnName": "burrow_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "climbSpeed",
|
|
||||||
"columnName": "climb_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "flySpeed",
|
|
||||||
"columnName": "fly_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "canHover",
|
|
||||||
"columnName": "can_hover",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "swimSpeed",
|
|
||||||
"columnName": "swim_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "hasCustomSpeed",
|
|
||||||
"columnName": "has_custom_speed",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customSpeedDescription",
|
|
||||||
"columnName": "custom_speed_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "challengeRating",
|
|
||||||
"columnName": "challenge_rating",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'1'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customChallengeRatingDescription",
|
|
||||||
"columnName": "custom_challenge_rating_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "customProficiencyBonus",
|
|
||||||
"columnName": "custom_proficiency_bonus",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "telepathyRange",
|
|
||||||
"columnName": "telepathy_range",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "understandsButDescription",
|
|
||||||
"columnName": "understands_but_description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "''"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "senses",
|
|
||||||
"columnName": "senses",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "skills",
|
|
||||||
"columnName": "skills",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageImmunities",
|
|
||||||
"columnName": "damage_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageResistances",
|
|
||||||
"columnName": "damage_resistances",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "damageVulnerabilities",
|
|
||||||
"columnName": "damage_vulnerabilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "conditionImmunities",
|
|
||||||
"columnName": "condition_immunities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "languages",
|
|
||||||
"columnName": "languages",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "abilities",
|
|
||||||
"columnName": "abilities",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "actions",
|
|
||||||
"columnName": "actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "reactions",
|
|
||||||
"columnName": "reactions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "lairActions",
|
|
||||||
"columnName": "lair_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "legendaryActions",
|
|
||||||
"columnName": "legendary_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "regionalActions",
|
|
||||||
"columnName": "regional_actions",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false,
|
|
||||||
"defaultValue": "'[]'"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ftsVersion": "FTS4",
|
|
||||||
"ftsOptions": {
|
|
||||||
"tokenizer": "simple",
|
|
||||||
"tokenizerArgs": [],
|
|
||||||
"contentTable": "monsters",
|
|
||||||
"languageIdColumnName": "",
|
|
||||||
"matchInfo": "FTS4",
|
|
||||||
"notIndexedColumns": [],
|
|
||||||
"prefixSizes": [],
|
|
||||||
"preferredOrder": "ASC"
|
|
||||||
},
|
|
||||||
"contentSyncTriggers": [
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_BEFORE_UPDATE BEFORE UPDATE ON `monsters` BEGIN DELETE FROM `monsters_fts` WHERE `docid`=OLD.`rowid`; END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_BEFORE_DELETE BEFORE DELETE ON `monsters` BEGIN DELETE FROM `monsters_fts` WHERE `docid`=OLD.`rowid`; END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_AFTER_UPDATE AFTER UPDATE ON `monsters` BEGIN INSERT INTO `monsters_fts`(`docid`, `name`, `size`, `type`, `subtype`, `alignment`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`size`, NEW.`type`, NEW.`subtype`, NEW.`alignment`); END",
|
|
||||||
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_monsters_fts_AFTER_INSERT AFTER INSERT ON `monsters` BEGIN INSERT INTO `monsters_fts`(`docid`, `name`, `size`, `type`, `subtype`, `alignment`) VALUES (NEW.`rowid`, NEW.`name`, NEW.`size`, NEW.`type`, NEW.`subtype`, NEW.`alignment`); END"
|
|
||||||
],
|
|
||||||
"tableName": "monsters_fts",
|
|
||||||
"createSql": "CREATE VIRTUAL TABLE IF NOT EXISTS `${TABLE_NAME}` USING FTS4(`name` TEXT, `size` TEXT, `type` TEXT, `subtype` TEXT, `alignment` TEXT, content=`monsters`)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "size",
|
|
||||||
"columnName": "size",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "type",
|
|
||||||
"columnName": "type",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "subtype",
|
|
||||||
"columnName": "subtype",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "alignment",
|
|
||||||
"columnName": "alignment",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7c3c3ed79c7002102e7af7cfd21c23e0')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
## Monster
|
|
||||||
id: UUID as TEXT // doesn't exist in the iOS model
|
|
||||||
abilities: Set<Trait> converted to JSON as TEXT
|
|
||||||
actions: Set<Trait> converted to JSON as TEXT
|
|
||||||
alignment: String as TEXT
|
|
||||||
armor_type: Enum<String> as TEXT
|
|
||||||
blindsight_range: int as INTEGER
|
|
||||||
burrow_speed: int as INTEGER
|
|
||||||
can_hover: boolean as INTEGER
|
|
||||||
challenge_rating: Enum<String> as TEXT
|
|
||||||
charisma_saving_throw_advantage
|
|
||||||
charisma_saving_throw_proficiency
|
|
||||||
charisma_score: int as INTEGER
|
|
||||||
climb_speed: int as INTEGER
|
|
||||||
condition_immunities: Set<String> converted to JSON as TEXT
|
|
||||||
constitution_saving_throw_advantage
|
|
||||||
constitution_saving_throw_proficiency
|
|
||||||
constitution_score: int as INTEGER
|
|
||||||
//other_armor_description: String as TEXT
|
|
||||||
custom_challenge_rating_description: String as TEXT
|
|
||||||
custom_hit_points_description: String
|
|
||||||
custom_proficiency_bonus: int as INTEGER
|
|
||||||
custom_speed_description: String as TEXT
|
|
||||||
damage_immunities: Set<String> converted to JSON as TEXT
|
|
||||||
damage_resistances: Set<String> converted to JSON as TEXT
|
|
||||||
damage_vulnerabilities: Set<String> converted to JSON as TEXT
|
|
||||||
darkvision_range: int as INTEGER
|
|
||||||
dexterity_saving_throw_advantage
|
|
||||||
dexterity_saving_throw_proficiency
|
|
||||||
dexterity_score: int as INTEGER
|
|
||||||
fly_speed: int as INTEGER
|
|
||||||
has_custom_hit_points: boolean as INTEGER
|
|
||||||
has_custom_speed: boolean as INTEGER
|
|
||||||
// has_shield
|
|
||||||
hit_dice: int as INTEGER
|
|
||||||
intelligence_saving_throw_advantage
|
|
||||||
intelligence_saving_throw_proficiency
|
|
||||||
intelligence_score: int as INTEGER
|
|
||||||
is_blind_beyond_blindsight_range: boolean as INTEGER
|
|
||||||
lair_actions
|
|
||||||
languages: Set<Language> converted to JSON as TEXT
|
|
||||||
legendary_actions
|
|
||||||
name: String as TEXT
|
|
||||||
natural_armor_bonus: int as INTEGER
|
|
||||||
other_armor_description: String as TEXT
|
|
||||||
reactions
|
|
||||||
regional_actions
|
|
||||||
// senses
|
|
||||||
shield_bonus: int as INTEGER
|
|
||||||
size: String as TEXT
|
|
||||||
strength_saving_throw_advantage
|
|
||||||
strength_saving_throw_proficiency
|
|
||||||
strength_score: int as INTEGER
|
|
||||||
tag: String as TEXT // subtype || tag
|
|
||||||
swim_speed: int as INTEGER
|
|
||||||
telepathy_range: int as INTEGER
|
|
||||||
tremorsense_range: int as INTEGER
|
|
||||||
truesight_range: int as INTEGER
|
|
||||||
type: String as TEXT
|
|
||||||
understands_but_description: String as TEXT
|
|
||||||
walk_speed: int as INTEGER
|
|
||||||
wisdom_saving_throw_advantage
|
|
||||||
wisdom_saving_throw_proficiency
|
|
||||||
wisdom_score: int as INTEGER
|
|
||||||
|
|
||||||
// tracked as relationship (don't do this)
|
|
||||||
skills: Set<Skill> converted to JSON as TEXT
|
|
||||||
|
|
||||||
## Skill
|
|
||||||
// ability_score_name String defaults to "strength"
|
|
||||||
// advantage String defaults to "none"
|
|
||||||
// name String defaults to ""
|
|
||||||
// proficiency String defaults to "none"
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ExampleInstrumentedTest {
|
|
||||||
@Test
|
|
||||||
public void useAppContext() {
|
|
||||||
// Context of the app under test.
|
|
||||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
|
||||||
assertEquals("com.majinnaibu.monstercards", appContext.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.init;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.BuildConfig;
|
|
||||||
import com.microsoft.appcenter.AppCenter;
|
|
||||||
import com.microsoft.appcenter.analytics.Analytics;
|
|
||||||
import com.microsoft.appcenter.crashes.Crashes;
|
|
||||||
|
|
||||||
public class AppCenterInitializer {
|
|
||||||
|
|
||||||
public static void init(Application app) {
|
|
||||||
if (BuildConfig.APPCENTER_SECRET != null && !"".equals(BuildConfig.APPCENTER_SECRET)) {
|
|
||||||
AppCenter.start(
|
|
||||||
app,
|
|
||||||
BuildConfig.APPCENTER_SECRET,
|
|
||||||
Analytics.class,
|
|
||||||
Crashes.class
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.init;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDestination;
|
|
||||||
|
|
||||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
|
||||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
|
||||||
import com.facebook.flipper.core.FlipperClient;
|
|
||||||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
|
||||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.navigation.NavigationFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
|
||||||
import com.facebook.soloader.SoLoader;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.majinnaibu.monstercards.BuildConfig;
|
|
||||||
|
|
||||||
public class FlipperInitializer {
|
|
||||||
|
|
||||||
public static void init(Context ctx) {
|
|
||||||
SoLoader.init(ctx, false);
|
|
||||||
|
|
||||||
if (BuildConfig.DEBUG && FlipperUtils.shouldEnableFlipper(ctx)) {
|
|
||||||
final FlipperClient client = AndroidFlipperClient.getInstance(ctx);
|
|
||||||
client.addPlugin(new InspectorFlipperPlugin(ctx, DescriptorMapping.withDefaults()));
|
|
||||||
client.addPlugin(new DatabasesFlipperPlugin(ctx));
|
|
||||||
client.addPlugin(new SharedPreferencesFlipperPlugin(ctx));
|
|
||||||
client.addPlugin(NavigationFlipperPlugin.getInstance());
|
|
||||||
client.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendNavigationEvent(NavController controller, NavDestination destination, Bundle arguments) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
String json = gson.toJson(arguments != null ? arguments : new Bundle());
|
|
||||||
NavigationFlipperPlugin.getInstance().sendNavigationEvent(String.format("%s:%s", destination.getLabel(), json), null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.majinnaibu.monstercards">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:name=".MonsterCardsApplication"
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:fullBackupOnly="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:exported="true"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:launchMode="singleTask">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.SEND" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<data android:mimeType="text/plain" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<action android:name="android.intent.action.EDIT" />
|
|
||||||
<action android:name="android.intent.action.PICK" />
|
|
||||||
<action android:name="android.intent.action.INSERT" />
|
|
||||||
<action android:name="android.intent.action.INSERT_OR_EDIT" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.ALTERNATIVE" />
|
|
||||||
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
|
|
||||||
<data
|
|
||||||
android:mimeType="text/plain"
|
|
||||||
android:scheme="content" />
|
|
||||||
<data
|
|
||||||
android:mimeType="application/octet-stream"
|
|
||||||
android:scheme="content" />
|
|
||||||
<data
|
|
||||||
android:mimeType="text/plain"
|
|
||||||
android:scheme="file" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<nav-graph android:value="@navigation/mobile_navigation" />
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
|
|
||||||
android:exported="true" />
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards;
|
|
||||||
|
|
||||||
import androidx.room.Database;
|
|
||||||
import androidx.room.RoomDatabase;
|
|
||||||
import androidx.room.TypeConverters;
|
|
||||||
|
|
||||||
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.SetOfSkillConverter;
|
|
||||||
import com.majinnaibu.monstercards.data.converters.SetOfStringConverter;
|
|
||||||
import com.majinnaibu.monstercards.data.converters.UUIDConverter;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.models.MonsterFTS;
|
|
||||||
|
|
||||||
@Database(entities = {Monster.class, MonsterFTS.class}, version = 3)
|
|
||||||
@TypeConverters({
|
|
||||||
ArmorTypeConverter.class,
|
|
||||||
ChallengeRatingConverter.class,
|
|
||||||
ListOfTraitsConverter.class,
|
|
||||||
SetOfLanguageConverter.class,
|
|
||||||
SetOfSkillConverter.class,
|
|
||||||
SetOfStringConverter.class,
|
|
||||||
UUIDConverter.class,
|
|
||||||
})
|
|
||||||
public abstract class AppDatabase extends RoomDatabase {
|
|
||||||
public abstract MonsterDAO monsterDAO();
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.provider.DocumentsContract;
|
|
||||||
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;
|
|
||||||
import androidx.navigation.fragment.NavHostFragment;
|
|
||||||
import androidx.navigation.ui.AppBarConfiguration;
|
|
||||||
import androidx.navigation.ui.NavigationUI;
|
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
|
||||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
|
||||||
import com.majinnaibu.monstercards.init.AppCenterInitializer;
|
|
||||||
import com.majinnaibu.monstercards.init.FlipperInitializer;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
|
||||||
if (item.getItemId() == android.R.id.home) {
|
|
||||||
getOnBackPressedDispatcher().onBackPressed();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
AppCenterInitializer.init(getApplication());
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
BottomNavigationView navView = findViewById(R.id.nav_view);
|
|
||||||
// Passing each menu ID as a set of Ids because each
|
|
||||||
// menu should be considered as top level destinations.
|
|
||||||
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
|
|
||||||
R.id.navigation_search,
|
|
||||||
R.id.navigation_dashboard,
|
|
||||||
R.id.navigation_collections,
|
|
||||||
R.id.navigation_library)
|
|
||||||
.build();
|
|
||||||
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
|
|
||||||
NavController navController = navHostFragment.getNavController();
|
|
||||||
navController.addOnDestinationChangedListener(FlipperInitializer::sendNavigationEvent);
|
|
||||||
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
|
|
||||||
NavigationUI.setupWithNavController(navView, navController);
|
|
||||||
onNewIntent(getIntent());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onNewIntent(Intent intent) {
|
|
||||||
super.onNewIntent(intent);
|
|
||||||
|
|
||||||
String json = readMonsterJSONFromIntent(intent);
|
|
||||||
if (!StringHelper.isNullOrEmpty(json)) {
|
|
||||||
NavHostFragment navHostFragment = Objects.requireNonNull((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) {
|
|
||||||
String action = intent.getAction();
|
|
||||||
Bundle extras = intent.getExtras();
|
|
||||||
String type = intent.getType();
|
|
||||||
String json;
|
|
||||||
Uri uri = null;
|
|
||||||
if ("android.intent.action.MAIN".equals(action)) {
|
|
||||||
return null;
|
|
||||||
} else if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
|
|
||||||
uri = extras.getParcelable("android.intent.extra.STREAM");
|
|
||||||
} else if ("android.intent.action.VIEW".equals(action) && ("text/plain".equals(type) || "application/octet-stream".equals(type))) {
|
|
||||||
uri = intent.getData();
|
|
||||||
} else {
|
|
||||||
Logger.logError(String.format("unexpected launch configuration action: %s, type: %s", action, type));
|
|
||||||
}
|
|
||||||
if (uri == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
json = readContentsOfUri(uri);
|
|
||||||
if (StringHelper.isNullOrEmpty(json)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String readContentsOfUri(Uri uri) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
try (
|
|
||||||
InputStream inputStream = openInputStream(uri);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(inputStream)))
|
|
||||||
) {
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
builder.append(line);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Logger.logError("error reading file", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isVirtualFile(Uri uri) {
|
|
||||||
if (!DocumentsContract.isDocumentUri(this, uri)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = getContentResolver().query(
|
|
||||||
uri,
|
|
||||||
new String[]{DocumentsContract.Document.COLUMN_FLAGS},
|
|
||||||
null, null, null);
|
|
||||||
|
|
||||||
int flags = 0;
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
flags = cursor.getInt(0);
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
|
|
||||||
return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InputStream openInputStream(Uri uri) throws IOException {
|
|
||||||
ContentResolver resolver = getContentResolver();
|
|
||||||
if (isVirtualFile(uri)) {
|
|
||||||
String[] openableMimeTypes = resolver.getStreamTypes(uri, "*/*");
|
|
||||||
if (openableMimeTypes == null || openableMimeTypes.length <= 0) {
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
}
|
|
||||||
return resolver.openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null).createInputStream();
|
|
||||||
} else {
|
|
||||||
return resolver.openInputStream(uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
public MonsterCardsApplication() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public MonsterRepository getMonsterRepository() {
|
|
||||||
return m_monsterLibraryRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the application is starting, before any other application objects have been created.
|
|
||||||
// Overriding this method is totally optional!
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the system when the device configuration changes while your component is running.
|
|
||||||
// Overriding this method is totally optional!
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
|
||||||
super.onConfigurationChanged(newConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called when the overall system is running low on memory,
|
|
||||||
// and would like actively running processes to tighten their belts.
|
|
||||||
// Overriding this method is totally optional!
|
|
||||||
@Override
|
|
||||||
public void onLowMemory() {
|
|
||||||
super.onLowMemory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
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;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
|
||||||
import com.majinnaibu.monstercards.models.Language;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.models.Skill;
|
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public final class DevContent {
|
|
||||||
@NonNull
|
|
||||||
public static Monster createSampleMonster() {
|
|
||||||
Monster monster = new Monster();
|
|
||||||
// Name
|
|
||||||
monster.name = "Pixie";
|
|
||||||
// Meta
|
|
||||||
monster.size = "tiny";
|
|
||||||
monster.type = "fey";
|
|
||||||
monster.subtype = "";
|
|
||||||
monster.alignment = "neutral good";
|
|
||||||
monster.armorType = ArmorType.NONE;
|
|
||||||
// Armor & Armor Class
|
|
||||||
monster.shieldBonus = 0;
|
|
||||||
monster.naturalArmorBonus = 7;
|
|
||||||
monster.otherArmorDescription = "14";
|
|
||||||
// Hit Points
|
|
||||||
monster.hitDice = 1;
|
|
||||||
monster.hasCustomHP = false;
|
|
||||||
monster.customHPDescription = "11 (2d8 + 2)";
|
|
||||||
monster.walkSpeed = 10;
|
|
||||||
monster.burrowSpeed = 0;
|
|
||||||
monster.climbSpeed = 0;
|
|
||||||
monster.flySpeed = 30;
|
|
||||||
monster.canHover = false;
|
|
||||||
monster.swimSpeed = 0;
|
|
||||||
monster.hasCustomSpeed = false;
|
|
||||||
monster.customSpeedDescription = "30 ft., swim 30 ft.";
|
|
||||||
// Ability Scores
|
|
||||||
monster.strengthScore = Integer.parseInt("2");
|
|
||||||
monster.dexterityScore = Integer.parseInt("20");
|
|
||||||
monster.constitutionScore = Integer.parseInt("8");
|
|
||||||
monster.intelligenceScore = Integer.parseInt("10");
|
|
||||||
monster.wisdomScore = Integer.parseInt("14");
|
|
||||||
monster.charismaScore = Integer.parseInt("15");
|
|
||||||
// monster.strengthScore = 10;
|
|
||||||
// monster.dexterityScore = 10;
|
|
||||||
// monster.constitutionScore = 10;
|
|
||||||
// monster.intelligenceScore = 10;
|
|
||||||
// monster.wisdomScore = 10;
|
|
||||||
// monster.charismaScore = 10;
|
|
||||||
|
|
||||||
// Saving Throws
|
|
||||||
monster.strengthSavingThrowAdvantage = AdvantageType.NONE;
|
|
||||||
monster.strengthSavingThrowProficiency = ProficiencyType.NONE;
|
|
||||||
monster.dexteritySavingThrowAdvantage = AdvantageType.ADVANTAGE;
|
|
||||||
monster.dexteritySavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
monster.constitutionSavingThrowAdvantage = AdvantageType.DISADVANTAGE;
|
|
||||||
monster.constitutionSavingThrowProficiency = ProficiencyType.EXPERTISE;
|
|
||||||
monster.intelligenceSavingThrowAdvantage = AdvantageType.NONE;
|
|
||||||
monster.intelligenceSavingThrowProficiency = ProficiencyType.EXPERTISE;
|
|
||||||
monster.wisdomSavingThrowAdvantage = AdvantageType.ADVANTAGE;
|
|
||||||
monster.wisdomSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
monster.charismaSavingThrowAdvantage = AdvantageType.DISADVANTAGE;
|
|
||||||
monster.charismaSavingThrowProficiency = ProficiencyType.NONE;
|
|
||||||
//Skills
|
|
||||||
monster.skills.add(new Skill("perception", AbilityScore.WISDOM));
|
|
||||||
monster.skills.add(new Skill("stealth", AbilityScore.DEXTERITY));
|
|
||||||
// Damage Types
|
|
||||||
monster.damageImmunities.add("force");
|
|
||||||
monster.damageImmunities.add("lightning");
|
|
||||||
monster.damageImmunities.add("poison");
|
|
||||||
monster.damageResistances.add("cold");
|
|
||||||
monster.damageResistances.add("fire");
|
|
||||||
monster.damageResistances.add("piercing");
|
|
||||||
monster.damageVulnerabilities.add("acid");
|
|
||||||
monster.damageVulnerabilities.add("bludgeoning");
|
|
||||||
monster.damageVulnerabilities.add("necrotic");
|
|
||||||
// Condition Immunities
|
|
||||||
monster.conditionImmunities.add("blinded");
|
|
||||||
// Senses
|
|
||||||
monster.senses.add("blindsight 10 ft. (blind beyond this range)");
|
|
||||||
monster.senses.add("darkvision 20 ft.");
|
|
||||||
monster.senses.add("tremorsense 30 ft.");
|
|
||||||
monster.senses.add("truesight 40 ft.");
|
|
||||||
monster.telepathyRange = 20;
|
|
||||||
monster.understandsButDescription = "doesn't care";
|
|
||||||
// Languages
|
|
||||||
monster.languages.add(new Language("English", true));
|
|
||||||
monster.languages.add(new Language("Steve", false));
|
|
||||||
monster.languages.add(new Language("Spanish", true));
|
|
||||||
monster.languages.add(new Language("French", true));
|
|
||||||
monster.languages.add(new Language("Mermataur", false));
|
|
||||||
monster.languages.add(new Language("Goldfish", false));
|
|
||||||
// Challenge Rating
|
|
||||||
monster.challengeRating = ChallengeRating.CUSTOM;
|
|
||||||
monster.customChallengeRatingDescription = "Infinite (0XP)";
|
|
||||||
monster.customProficiencyBonus = 4;
|
|
||||||
// Abilities
|
|
||||||
monster.abilities.add(new Trait("Spellcasting", "The acolyte is a 1st-level spellcaster. Its spellcasting ability is Wisdom (spell save DC [WIS SAVE], [WIS ATK] to hit with spell attacks). The acolyte has following cleric spells prepared:\n\n\n> Cantrips (at will): _light, sacred flame, thaumaturgy_\n> 1st level (3 slots): _bless, cure wounds, sanctuary_"));
|
|
||||||
monster.abilities.add(new Trait("Amphibious", "The dragon can breathe air and water."));
|
|
||||||
monster.abilities.add(new Trait("Legendary Resistance (3/Day)", "If the dragon fails a saving throw, it can choose to succeed instead."));
|
|
||||||
// Actions
|
|
||||||
monster.actions.add(new Trait("Club", "_Melee Weapon Attack:_ [STR ATK] to hit, reach 5 ft., one target. _Hit:_ 2 (1d4) bludgeoning damage."));
|
|
||||||
|
|
||||||
return monster;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.room.Dao;
|
|
||||||
import androidx.room.Delete;
|
|
||||||
import androidx.room.Insert;
|
|
||||||
import androidx.room.OnConflictStrategy;
|
|
||||||
import androidx.room.Query;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Completable;
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
public interface MonsterDAO {
|
|
||||||
@Query("SELECT * FROM monsters")
|
|
||||||
Flowable<List<Monster>> getAll();
|
|
||||||
|
|
||||||
@Query("SELECT * FROM monsters WHERE id IN (:monsterIds)")
|
|
||||||
Flowable<List<Monster>> loadAllByIds(String[] monsterIds);
|
|
||||||
|
|
||||||
@Query("SELECT * FROM monsters WHERE name LIKE :name LIMIT 1")
|
|
||||||
Flowable<Monster> findByName(String name);
|
|
||||||
|
|
||||||
@Query("SELECT monsters.* FROM monsters JOIN monsters_fts ON monsters.oid = monsters_fts.docid WHERE monsters_fts MATCH :searchText")
|
|
||||||
Flowable<List<Monster>> search(String searchText);
|
|
||||||
|
|
||||||
@Insert
|
|
||||||
Completable insertAll(Monster... monsters);
|
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
|
||||||
Completable save(Monster... monsters);
|
|
||||||
|
|
||||||
@Delete
|
|
||||||
Completable delete(Monster monster);
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
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;
|
|
||||||
|
|
||||||
public MonsterRepository(@NonNull AppDatabase db) {
|
|
||||||
m_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Flowable<List<Monster>> getMonsters() {
|
|
||||||
return m_db.monsterDAO()
|
|
||||||
.getAll()
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
})
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Flowable<Monster> getMonster(@NonNull UUID monsterId) {
|
|
||||||
return m_db.monsterDAO()
|
|
||||||
.loadAllByIds(new String[]{monsterId.toString()})
|
|
||||||
.map(
|
|
||||||
monsters -> {
|
|
||||||
if (monsters.size() > 0) {
|
|
||||||
return monsters.get(0);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Completable addMonster(Monster monster) {
|
|
||||||
Completable result = m_db.monsterDAO().insertAll(monster);
|
|
||||||
result.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Completable deleteMonster(Monster monster) {
|
|
||||||
Completable result = m_db.monsterDAO().delete(monster);
|
|
||||||
result.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Completable saveMonster(Monster monster) {
|
|
||||||
Completable result = m_db.monsterDAO().save(monster);
|
|
||||||
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,19 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.converters;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.room.TypeConverter;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ArmorType;
|
|
||||||
|
|
||||||
public class ArmorTypeConverter {
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromArmorType(@NonNull ArmorType armorType) {
|
|
||||||
return armorType.stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static ArmorType armorTypeFromStringValue(String stringValue) {
|
|
||||||
return ArmorType.valueOfString(stringValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.converters;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.room.TypeConverter;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
|
||||||
|
|
||||||
public class ChallengeRatingConverter {
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromChallengeRating(@NonNull ChallengeRating challengeRating) {
|
|
||||||
return challengeRating.stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static ChallengeRating challengeRatingFromStringValue(String stringValue) {
|
|
||||||
return ChallengeRating.valueOfString(stringValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
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.Trait;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ListOfTraitsConverter {
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromListOfTraits(List<Trait> traits) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
return gson.toJson(traits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static List<Trait> listOfTraitsFromString(String string) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
Type setType = new TypeToken<ArrayList<Trait>>() {
|
|
||||||
}.getType();
|
|
||||||
return gson.fromJson(string, setType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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.Language;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class SetOfLanguageConverter {
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromSetOfLanguage(Set<Language> languages) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
return gson.toJson(languages);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static Set<Language> setOfLanguageFromString(String string) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
Type setType = new TypeToken<HashSet<Language>>() {
|
|
||||||
}.getType();
|
|
||||||
return gson.fromJson(string, setType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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.Skill;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class SetOfSkillConverter {
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromSetOfSkill(Set<Skill> skills) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
return gson.toJson(skills);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static Set<Skill> setOfSkillFromString(String string) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
Type setType = new TypeToken<HashSet<Skill>>() {
|
|
||||||
}.getType();
|
|
||||||
return gson.fromJson(string, setType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.converters;
|
|
||||||
|
|
||||||
import androidx.room.TypeConverter;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class SetOfStringConverter {
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static String fromSetOfString(Set<String> strings) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
return gson.toJson(strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static Set<String> setOfStringFromString(String string) {
|
|
||||||
Gson gson = new Gson();
|
|
||||||
Type setType = new TypeToken<HashSet<String>>() {
|
|
||||||
}.getType();
|
|
||||||
return gson.fromJson(string, setType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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) {
|
|
||||||
return uuid.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@TypeConverter
|
|
||||||
public static UUID uuidFromString(String string) {
|
|
||||||
return UUID.fromString(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public enum AbilityScore {
|
|
||||||
STRENGTH("strength", "Strength", "STR"),
|
|
||||||
DEXTERITY("dexterity", "Dexterity", "DEX"),
|
|
||||||
CONSTITUTION("constitution", "Constitution", "CON"),
|
|
||||||
INTELLIGENCE("intelligence", "Intelligence", "INT"),
|
|
||||||
WISDOM("wisdom", "Wisdom", "WIS"),
|
|
||||||
CHARISMA("charisma", "Charisma", "CHA"),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String displayName;
|
|
||||||
public final String shortDisplayName;
|
|
||||||
public final String stringValue;
|
|
||||||
|
|
||||||
AbilityScore(String stringValue, String displayName, String shortDisplayName) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
this.shortDisplayName = shortDisplayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AbilityScore valueOfString(String string) {
|
|
||||||
for (AbilityScore abilityScore : values()) {
|
|
||||||
if (abilityScore.stringValue.equals(string)) {
|
|
||||||
return abilityScore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AbilityScore.STRENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
public enum AdvantageType {
|
|
||||||
NONE("none", "None", ""),
|
|
||||||
ADVANTAGE("advantage", "Advantage", "A"),
|
|
||||||
DISADVANTAGE("disadvantage", "Disadvantage", "D"),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String displayName;
|
|
||||||
public final String stringValue;
|
|
||||||
public final String label;
|
|
||||||
|
|
||||||
AdvantageType(String stringValue, String displayName, String label) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AdvantageType valueOfString(String string) {
|
|
||||||
for (AdvantageType advantageType : values()) {
|
|
||||||
if (advantageType.stringValue.equals(string)) {
|
|
||||||
return advantageType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AdvantageType.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public enum ArmorType {
|
|
||||||
NONE("none", "None", 10),
|
|
||||||
NATURAL_ARMOR("natural armor", "Natural Armor", 10),
|
|
||||||
MAGE_ARMOR("mage armor", "Mage Armor", 10),
|
|
||||||
PADDED("padded", "Padded", 11),
|
|
||||||
LEATHER("leather", "Leather", 11),
|
|
||||||
STUDDED_LEATHER("studded", "Studded Leather", 12),
|
|
||||||
HIDE("hide", "Hide", 12),
|
|
||||||
CHAIN_SHIRT("chain shirt", "Chain Shirt", 13),
|
|
||||||
SCALE_MAIL("scale mail", "Scale Mail", 14),
|
|
||||||
BREASTPLATE("breastplate", "Breastplate", 14),
|
|
||||||
HALF_PLATE("half plate", "Half Plate", 15),
|
|
||||||
RING_MAIL("ring mail", "Ring Mail", 14),
|
|
||||||
CHAIN_MAIL("chain mail", "Chain Mail", 16),
|
|
||||||
SPLINT_MAIL("splint", "Splint Mail", 17),
|
|
||||||
PLATE_MAIL("plate", "Plate Mail", 18),
|
|
||||||
OTHER("other", "Other", 10),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String displayName;
|
|
||||||
public final String stringValue;
|
|
||||||
public final int baseArmorClass;
|
|
||||||
|
|
||||||
ArmorType(String stringValue, String displayName, int baseArmorClass) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
this.baseArmorClass = baseArmorClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArmorType valueOfString(String string) {
|
|
||||||
for (ArmorType armorType : values()) {
|
|
||||||
if (armorType.stringValue.equals(string)) {
|
|
||||||
return armorType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ArmorType.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public enum ChallengeRating {
|
|
||||||
CUSTOM("custom", "Custom", 0),
|
|
||||||
ZERO("zero", "0 (10 XP)", 2),
|
|
||||||
ONE_EIGHTH("1/8", "1/8 (25 XP)", 2),
|
|
||||||
ONE_QUARTER("1/4", "1/4 (50 XP)", 2),
|
|
||||||
ONE_HALF("1/2", "1/2 (100 XP)", 2),
|
|
||||||
ONE("1", "1 (200 XP)", 2),
|
|
||||||
TWO("2", "2 (450 XP)", 2),
|
|
||||||
THREE("3", "3 (700 XP)", 2),
|
|
||||||
FOUR("4", "4 (1,100 XP)", 2),
|
|
||||||
FIVE("5", "5 (1,800 XP)", 3),
|
|
||||||
SIX("6", "6 (2,300 XP)", 3),
|
|
||||||
SEVEN("7", "7 (2,900 XP)", 3),
|
|
||||||
EIGHT("8", "8 (3,900 XP)", 3),
|
|
||||||
NINE("9", "9 (5,000 XP)", 4),
|
|
||||||
TEN("10", "10 (5,900 XP)", 4),
|
|
||||||
ELEVEN("11", "11 (7,200 XP)", 4),
|
|
||||||
TWELVE("12", "12 (8,400 XP)", 4),
|
|
||||||
THIRTEEN("13", "13 (10,000 XP)", 5),
|
|
||||||
FOURTEEN("14", "14 (11,500 XP)", 5),
|
|
||||||
FIFTEEN("15", "15 (13,000 XP)", 5),
|
|
||||||
SIXTEEN("16", "16 (15,000 XP)", 5),
|
|
||||||
SEVENTEEN("17", "17 (18,000 XP)", 6),
|
|
||||||
EIGHTEEN("18", "18 (20,000 XP)", 6),
|
|
||||||
NINETEEN("19", "19 (22,000 XP)", 6),
|
|
||||||
TWENTY("20", "20 (25,000 XP)", 6),
|
|
||||||
TWENTY_ONE("21", "21 (33,000 XP)", 7),
|
|
||||||
TWENTY_TWO("22", "22 (41,000 XP)", 7),
|
|
||||||
TWENTY_THREE("23", "23 (50,000 XP)", 7),
|
|
||||||
TWENTY_FOUR("24", "24 (62,000 XP)", 7),
|
|
||||||
TWENTY_FIVE("25", "25 (75,000 XP)", 8),
|
|
||||||
TWENTY_SIX("26", "26 (90,000 XP)", 8),
|
|
||||||
TWENTY_SEVEN("27", "27 (105,000 XP)", 8),
|
|
||||||
TWENTY_EIGHT("28", "28 (120,000 XP)", 8),
|
|
||||||
TWENTY_NINE("29", "29 (135,000 XP)", 9),
|
|
||||||
THIRTY("30", "30 (155,000 XP)", 9),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String displayName;
|
|
||||||
public final String stringValue;
|
|
||||||
public final int proficiencyBonus;
|
|
||||||
|
|
||||||
ChallengeRating(String stringValue, String displayName, int proficiencyBonus) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
this.proficiencyBonus = proficiencyBonus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ChallengeRating valueOfString(String string) {
|
|
||||||
for (ChallengeRating challengeRating : values()) {
|
|
||||||
if (challengeRating.stringValue.equals(string)) {
|
|
||||||
return challengeRating;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ChallengeRating.ONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
public enum ProficiencyType {
|
|
||||||
NONE("none", "None", ""),
|
|
||||||
PROFICIENT("proficient", "Proficient", "P"),
|
|
||||||
EXPERTISE("expertise", "Expertise", "Ex"),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String displayName;
|
|
||||||
public final String stringValue;
|
|
||||||
public final String label;
|
|
||||||
|
|
||||||
ProficiencyType(String stringValue, String displayName, String label) {
|
|
||||||
this.displayName = displayName;
|
|
||||||
this.stringValue = stringValue;
|
|
||||||
this.label = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProficiencyType valueOfString(String string) {
|
|
||||||
for (ProficiencyType proficiencyType : values()) {
|
|
||||||
if (proficiencyType.stringValue.equals(string)) {
|
|
||||||
return proficiencyType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ProficiencyType.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
public enum StringType {
|
|
||||||
CONDITION_IMMUNITY,
|
|
||||||
DAMAGE_IMMUNITY,
|
|
||||||
DAMAGE_RESISTANCE,
|
|
||||||
DAMAGE_VULNERABILITY,
|
|
||||||
SENSE
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.data.enums;
|
|
||||||
|
|
||||||
public enum TraitType {
|
|
||||||
ABILITY,
|
|
||||||
ACTION,
|
|
||||||
LAIR_ACTION,
|
|
||||||
LEGENDARY_ACTION,
|
|
||||||
REGIONAL_ACTION,
|
|
||||||
REACTIONS
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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) {
|
|
||||||
for (int index = 0; index < array.length; index++) {
|
|
||||||
if (Objects.equals(array[index], target)) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.helpers;
|
|
||||||
|
|
||||||
import org.commonmark.node.Document;
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
import org.commonmark.node.Paragraph;
|
|
||||||
import org.commonmark.parser.Parser;
|
|
||||||
import org.commonmark.renderer.html.HtmlRenderer;
|
|
||||||
|
|
||||||
public final class CommonMarkHelper {
|
|
||||||
public static String toHtml(String rawCommonMark) {
|
|
||||||
Parser parser = Parser.builder().build();
|
|
||||||
Node document = parser.parse(rawCommonMark);
|
|
||||||
Node parent1 = document.getFirstChild();
|
|
||||||
Node parent2 = document.getLastChild();
|
|
||||||
if (parent1 == parent2 && parent1 instanceof Paragraph) {
|
|
||||||
document = new Document();
|
|
||||||
Node child = parent1.getFirstChild();
|
|
||||||
while (child != null) {
|
|
||||||
Node nextChild = child.getNext();
|
|
||||||
document.appendChild(child);
|
|
||||||
child = nextChild;//child.getNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
|
||||||
return renderer.render(document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,311 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.helpers;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.majinnaibu.monstercards.data.converters.ArmorTypeConverter;
|
|
||||||
import com.majinnaibu.monstercards.data.converters.ChallengeRatingConverter;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
|
||||||
import com.majinnaibu.monstercards.models.Language;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.models.Skill;
|
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
Monster monster = new Monster();
|
|
||||||
monster.name = Helpers.getString(rootDict, "name");
|
|
||||||
monster.size = Helpers.getString(rootDict, "size");
|
|
||||||
monster.type = Helpers.getString(rootDict, "type");
|
|
||||||
monster.subtype = Helpers.getString(rootDict, "tag");
|
|
||||||
monster.alignment = Helpers.getString(rootDict, "alignment");
|
|
||||||
monster.hitDice = Helpers.getInt(rootDict, "hitDice");
|
|
||||||
monster.armorType = ArmorTypeConverter.armorTypeFromStringValue(Helpers.getString(rootDict, "armorName"));
|
|
||||||
monster.shieldBonus = Helpers.getInt(rootDict, "shieldBonus");
|
|
||||||
monster.naturalArmorBonus = Helpers.getInt(rootDict, "natArmorBonus");
|
|
||||||
monster.otherArmorDescription = Helpers.getString(rootDict, "otherArmorDesc");
|
|
||||||
monster.walkSpeed = Helpers.getInt(rootDict, "speed");
|
|
||||||
monster.burrowSpeed = Helpers.getInt(rootDict, "burrowSpeed");
|
|
||||||
monster.climbSpeed = Helpers.getInt(rootDict, "climbSpeed");
|
|
||||||
monster.flySpeed = Helpers.getInt(rootDict, "flySpeed");
|
|
||||||
monster.canHover = Helpers.getBool(rootDict, "hover");
|
|
||||||
monster.swimSpeed = Helpers.getInt(rootDict, "swimSpeed");
|
|
||||||
monster.hasCustomHP = Helpers.getBool(rootDict, "customHP");
|
|
||||||
monster.hasCustomSpeed = Helpers.getBool(rootDict, "customSpeed");
|
|
||||||
monster.customHPDescription = Helpers.getString(rootDict, "hpText");
|
|
||||||
monster.customSpeedDescription = Helpers.getString(rootDict, "speedDesc");
|
|
||||||
monster.strengthScore = Helpers.getInt(rootDict, "strPoints");
|
|
||||||
monster.dexterityScore = Helpers.getInt(rootDict, "dexPoints");
|
|
||||||
monster.constitutionScore = Helpers.getInt(rootDict, "conPoints");
|
|
||||||
monster.intelligenceScore = Helpers.getInt(rootDict, "intPoints");
|
|
||||||
monster.wisdomScore = Helpers.getInt(rootDict, "wisPoints");
|
|
||||||
monster.charismaScore = Helpers.getInt(rootDict, "chaPoints");
|
|
||||||
Helpers.addSense(monster, rootDict, "blindsight");
|
|
||||||
// Helpers.getBool(rootDict, "blind");
|
|
||||||
Helpers.addSense(monster, rootDict, "darkvision");
|
|
||||||
Helpers.addSense(monster, rootDict, "tremorsense");
|
|
||||||
Helpers.addSense(monster, rootDict, "truesight");
|
|
||||||
monster.telepathyRange = Helpers.getInt(rootDict, "telepathy");
|
|
||||||
monster.challengeRating = ChallengeRatingConverter.challengeRatingFromStringValue(Helpers.getString(rootDict, "cr"));
|
|
||||||
monster.customChallengeRatingDescription = Helpers.getString(rootDict, "customCr");
|
|
||||||
monster.customProficiencyBonus = Helpers.getInt(rootDict, "customProf");
|
|
||||||
// Helpers.getBool(rootDict, "isLegendary");
|
|
||||||
// Helpers.getString(rootDict, "legendariesDescription");
|
|
||||||
// Helpers.getBool(rootDict, "isLair");
|
|
||||||
// Helpers.getString(rootDict, "lairDescription");
|
|
||||||
// Helpers.getString(rootDict, "lairDescriptionEnd");
|
|
||||||
// Helpers.getBool(rootDict, "isRegional");
|
|
||||||
// Helpers.getString(rootDict, "regionalDescription");
|
|
||||||
// Helpers.getString(rootDict, "regionalDescriptionEnd");
|
|
||||||
// properties: []
|
|
||||||
monster.abilities = Helpers.getListOfTraits(rootDict, "abilities");
|
|
||||||
monster.actions = Helpers.getListOfTraits(rootDict, "actions");
|
|
||||||
monster.reactions = Helpers.getListOfTraits(rootDict, "reactions");
|
|
||||||
monster.legendaryActions = Helpers.getListOfTraits(rootDict, "legendaries");
|
|
||||||
monster.lairActions = Helpers.getListOfTraits(rootDict, "lairs");
|
|
||||||
monster.regionalActions = Helpers.getListOfTraits(rootDict, "regionals");
|
|
||||||
Helpers.addSavingThrows(monster, rootDict);
|
|
||||||
// skills: []
|
|
||||||
monster.skills = Helpers.getSetOfSkills(rootDict);
|
|
||||||
// damagetypes: []
|
|
||||||
// specialdamage: []
|
|
||||||
monster.damageImmunities = Helpers.getSetOfDamageTypes(rootDict, "damageTypes", "i");
|
|
||||||
monster.damageImmunities.addAll(Helpers.getSetOfDamageTypes(rootDict, "specialdamage", "i"));
|
|
||||||
monster.damageResistances = Helpers.getSetOfDamageTypes(rootDict, "damageTypes", "r");
|
|
||||||
monster.damageResistances.addAll(Helpers.getSetOfDamageTypes(rootDict, "specialdamage", "r"));
|
|
||||||
monster.damageVulnerabilities = Helpers.getSetOfDamageTypes(rootDict, "damageTypes", "v");
|
|
||||||
monster.damageVulnerabilities.addAll(Helpers.getSetOfDamageTypes(rootDict, "specialdamage", "v"));
|
|
||||||
// conditions: []
|
|
||||||
monster.conditionImmunities = Helpers.getSetOfDamageTypes(rootDict, "conditions");
|
|
||||||
// languages: []
|
|
||||||
monster.languages = Helpers.getSetOfLanguages(rootDict, "languages");
|
|
||||||
// understandsBut: ""
|
|
||||||
monster.understandsButDescription = Helpers.getString(rootDict, "understandsBut");
|
|
||||||
// shortName: ""
|
|
||||||
// doubleColumns: true
|
|
||||||
// separationPoint: -1
|
|
||||||
// damage: []
|
|
||||||
// pluralName: ""
|
|
||||||
|
|
||||||
return monster;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class Helpers {
|
|
||||||
public static String getString(JsonObject dict, String name) {
|
|
||||||
return getString(dict, name, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getString(@NonNull JsonObject dict, String name, String defaultValue) {
|
|
||||||
if (dict.has(name)) {
|
|
||||||
return dict.get(name).getAsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getInt(JsonObject dict, String name) {
|
|
||||||
return getInt(dict, name, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getInt(@NonNull JsonObject dict, String name, int defaultValue) {
|
|
||||||
if (dict.has(name)) {
|
|
||||||
JsonElement element = dict.get(name);
|
|
||||||
if (element.isJsonPrimitive()) {
|
|
||||||
JsonPrimitive rawValue = element.getAsJsonPrimitive();
|
|
||||||
if (rawValue.isNumber()) {
|
|
||||||
return rawValue.getAsInt();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
return rawValue.getAsInt();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getBool(JsonObject dict, String name) {
|
|
||||||
return getBool(dict, name, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getBool(@NonNull 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
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSense(Monster monster, JsonObject root, String name) {
|
|
||||||
int distance = Helpers.getInt(root, name);
|
|
||||||
if (distance > 0) {
|
|
||||||
monster.senses.add(Helpers.formatDistance(name, distance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static List<Trait> getListOfTraits(@NonNull JsonObject dict, String name) {
|
|
||||||
ArrayList<Trait> traits = new ArrayList<>();
|
|
||||||
if (dict.has(name)) {
|
|
||||||
JsonElement arrayElement = dict.get(name);
|
|
||||||
if (arrayElement.isJsonArray()) {
|
|
||||||
JsonArray array = arrayElement.getAsJsonArray();
|
|
||||||
int size = array.size();
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
JsonElement jsonElement = array.get(index);
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
String traitName = Helpers.getString(jsonObject, "name");
|
|
||||||
String description = Helpers.getString(jsonObject, "desc");
|
|
||||||
Trait trait = new Trait(traitName, description);
|
|
||||||
traits.add(trait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return traits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addSavingThrows(Monster monster, @NonNull JsonObject root) {
|
|
||||||
if (root.has("sthrows")) {
|
|
||||||
JsonElement arrayElement = root.get("sthrows");
|
|
||||||
if (arrayElement.isJsonArray()) {
|
|
||||||
JsonArray array = arrayElement.getAsJsonArray();
|
|
||||||
int size = array.size();
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
JsonElement jsonElement = array.get(index);
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
String name = Helpers.getString(jsonObject, "name");
|
|
||||||
if ("str".equals(name)) {
|
|
||||||
monster.strengthSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
} else if ("dex".equals(name)) {
|
|
||||||
monster.dexteritySavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
} else if ("con".equals(name)) {
|
|
||||||
monster.constitutionSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
} else if ("int".equals(name)) {
|
|
||||||
monster.intelligenceSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
} else if ("wis".equals(name)) {
|
|
||||||
monster.wisdomSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
} else if ("cha".equals(name)) {
|
|
||||||
monster.charismaSavingThrowProficiency = ProficiencyType.PROFICIENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Set<Skill> getSetOfSkills(@NonNull JsonObject root) {
|
|
||||||
HashSet<Skill> skills = new HashSet<>();
|
|
||||||
if (root.has("skills")) {
|
|
||||||
JsonElement arrayElement = root.get("skills");
|
|
||||||
if (arrayElement.isJsonArray()) {
|
|
||||||
JsonArray array = arrayElement.getAsJsonArray();
|
|
||||||
int size = array.size();
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
JsonElement jsonElement = array.get(index);
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
String name = Helpers.getString(jsonObject, "name");
|
|
||||||
String stat = Helpers.getString(jsonObject, "stat");
|
|
||||||
String note = Helpers.getString(jsonObject, "note");
|
|
||||||
|
|
||||||
Skill skill = new Skill(name, AbilityScore.valueOfString(stat), AdvantageType.NONE, " (ex)".equals(note) ? ProficiencyType.EXPERTISE : ProficiencyType.PROFICIENT);
|
|
||||||
skills.add(skill);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
HashSet<String> damageTypes = new HashSet<>();
|
|
||||||
if (root.has(name)) {
|
|
||||||
JsonElement arrayElement = root.get(name);
|
|
||||||
if (arrayElement.isJsonArray()) {
|
|
||||||
JsonArray array = arrayElement.getAsJsonArray();
|
|
||||||
int size = array.size();
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
JsonElement jsonElement = array.get(index);
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
String dtName = Helpers.getString(jsonObject, "name");
|
|
||||||
String dtType = Helpers.getString(jsonObject, "type");
|
|
||||||
if (type == null || type.equals(dtType)) {
|
|
||||||
damageTypes.add(dtName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return damageTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Set<Language> getSetOfLanguages(@NonNull JsonObject root, String name) {
|
|
||||||
HashSet<Language> languages = new HashSet<>();
|
|
||||||
if (root.has(name)) {
|
|
||||||
JsonElement arrayElement = root.get(name);
|
|
||||||
if (arrayElement.isJsonArray()) {
|
|
||||||
JsonArray array = arrayElement.getAsJsonArray();
|
|
||||||
int size = array.size();
|
|
||||||
for (int index = 0; index < size; index++) {
|
|
||||||
JsonElement jsonElement = array.get(index);
|
|
||||||
if (jsonElement.isJsonObject()) {
|
|
||||||
JsonObject jsonObject = jsonElement.getAsJsonObject();
|
|
||||||
String languageName = Helpers.getString(jsonObject, "name");
|
|
||||||
boolean canSpeak = Helpers.getBool(jsonObject, "speaks");
|
|
||||||
Language language = new Language(languageName, canSpeak);
|
|
||||||
languages.add(language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return languages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.helpers;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@SuppressWarnings({"RedundantIfStatement"})
|
|
||||||
public final class StringHelper {
|
|
||||||
public static boolean isNullOrEmpty(CharSequence value) {
|
|
||||||
if (value == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("".contentEquals(value)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String value) {
|
|
||||||
mName = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.models;
|
|
||||||
|
|
||||||
import androidx.room.Entity;
|
|
||||||
import androidx.room.Fts4;
|
|
||||||
|
|
||||||
@Entity(tableName = "monsters_fts")
|
|
||||||
@Fts4(contentEntity = Monster.class)
|
|
||||||
public class MonsterFTS {
|
|
||||||
public String name;
|
|
||||||
public String size;
|
|
||||||
public String type;
|
|
||||||
public String subtype;
|
|
||||||
public String alignment;
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
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> {
|
|
||||||
|
|
||||||
public String name;
|
|
||||||
public AbilityScore abilityScore;
|
|
||||||
public AdvantageType advantageType;
|
|
||||||
public ProficiencyType proficiencyType;
|
|
||||||
|
|
||||||
public Skill(String name, AbilityScore abilityScore) {
|
|
||||||
this(name, abilityScore, AdvantageType.NONE, ProficiencyType.PROFICIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Skill(String name, AbilityScore abilityScore, AdvantageType advantageType) {
|
|
||||||
this(name, abilityScore, advantageType, ProficiencyType.PROFICIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Skill(String name, AbilityScore abilityScore, AdvantageType advantageType, ProficiencyType proficiencyType) {
|
|
||||||
this.name = name;
|
|
||||||
this.abilityScore = abilityScore;
|
|
||||||
this.advantageType = advantageType;
|
|
||||||
this.proficiencyType = proficiencyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSkillBonus(Monster monster) {
|
|
||||||
int modifier = monster.getAbilityModifier(abilityScore);
|
|
||||||
switch (proficiencyType) {
|
|
||||||
case PROFICIENT:
|
|
||||||
return modifier + monster.getProficiencyBonus();
|
|
||||||
case EXPERTISE:
|
|
||||||
return modifier + monster.getProficiencyBonus() * 2;
|
|
||||||
case NONE:
|
|
||||||
default:
|
|
||||||
return modifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getText(Monster monster) {
|
|
||||||
int bonus = getSkillBonus(monster);
|
|
||||||
|
|
||||||
return String.format(
|
|
||||||
"%s%s %+d%s",
|
|
||||||
name.charAt(0),
|
|
||||||
name.substring(1),
|
|
||||||
bonus,
|
|
||||||
advantageType == AdvantageType.ADVANTAGE ? " A" : advantageType == AdvantageType.DISADVANTAGE ? " D" : ""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(Skill o) {
|
|
||||||
return this.name.compareToIgnoreCase(o.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(Skill o1, Skill o2) {
|
|
||||||
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,49 +0,0 @@
|
|||||||
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 String name;
|
|
||||||
public String description;
|
|
||||||
|
|
||||||
public Trait(String name, String description) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.collections;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
|
|
||||||
public class CollectionsFragment extends MCFragment {
|
|
||||||
|
|
||||||
private CollectionsViewModel collectionsViewModel;
|
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
|
||||||
ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
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);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.collections;
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
|
|
||||||
public class CollectionsViewModel extends ViewModel {
|
|
||||||
|
|
||||||
private final MutableLiveData<String> mText;
|
|
||||||
|
|
||||||
public CollectionsViewModel() {
|
|
||||||
mText = new MutableLiveData<>();
|
|
||||||
mText.setValue("This is collections fragment");
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getText() {
|
|
||||||
return mText;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
|
||||||
import com.majinnaibu.monstercards.helpers.ArrayHelper;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class AbilityScorePicker extends LinearLayout {
|
|
||||||
private final ViewHolder mHolder;
|
|
||||||
private OnValueChangedListener mOnValueChangedListener;
|
|
||||||
private AbilityScore mSelectedValue;
|
|
||||||
private String mLabel;
|
|
||||||
|
|
||||||
public AbilityScorePicker(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
mSelectedValue = AbilityScore.STRENGTH;
|
|
||||||
mOnValueChangedListener = null;
|
|
||||||
// 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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.label.setText(mLabel);
|
|
||||||
|
|
||||||
mHolder.spinner.setAdapter(new ArrayAdapter<AbilityScore>(getContext(), R.layout.dropdown_list_item, AbilityScore.values()) {
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
AbilityScore item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
AbilityScore item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getDropDownView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
setValue((AbilityScore) parent.getItemAtPosition(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
setValue(mSelectedValue = AbilityScore.STRENGTH);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.spinner.setSelection(ArrayHelper.indexOf(AbilityScore.values(), mSelectedValue));
|
|
||||||
|
|
||||||
setValue(AbilityScore.STRENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbilityScorePicker(@NonNull Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbilityScore getValue() {
|
|
||||||
return mSelectedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(AbilityScore value) {
|
|
||||||
if (value != mSelectedValue) {
|
|
||||||
mSelectedValue = value;
|
|
||||||
mHolder.spinner.setSelection(ArrayHelper.indexOf(AbilityScore.values(), value));
|
|
||||||
if (mOnValueChangedListener != null) {
|
|
||||||
mOnValueChangedListener.onValueChanged(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnValueChangedListener(OnValueChangedListener listener) {
|
|
||||||
mOnValueChangedListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLabel() {
|
|
||||||
return mLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLabel(String label) {
|
|
||||||
if (!Objects.equals(mLabel, label)) {
|
|
||||||
mLabel = label;
|
|
||||||
mHolder.label.setText(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueChangedListener {
|
|
||||||
void onValueChanged(AbilityScore value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
|
|
||||||
private final Spinner spinner;
|
|
||||||
private final TextView label;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
spinner = root.findViewById(R.id.spinner);
|
|
||||||
label = root.findViewById(R.id.label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RadioGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
|
||||||
|
|
||||||
import com.google.android.material.radiobutton.MaterialRadioButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class AdvantagePicker extends ConstraintLayout {
|
|
||||||
private final ViewHolder mHolder;
|
|
||||||
private OnValueChangedListener mOnValueChangedListener;
|
|
||||||
private AdvantageType mSelectedValue;
|
|
||||||
|
|
||||||
public AdvantagePicker(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
mSelectedValue = AdvantageType.NONE;
|
|
||||||
mOnValueChangedListener = null;
|
|
||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
View root = inflater.inflate(R.layout.component_advantage_picker, this, true);
|
|
||||||
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
setValue(AdvantageType.NONE);
|
|
||||||
mHolder.group.setOnCheckedChangeListener((group, checkedId) -> {
|
|
||||||
if (R.id.hasAdvantage == checkedId) {
|
|
||||||
setValue(AdvantageType.ADVANTAGE);
|
|
||||||
} else if (R.id.hasDisadvantage == checkedId) {
|
|
||||||
setValue(AdvantageType.DISADVANTAGE);
|
|
||||||
} else {
|
|
||||||
setValue(AdvantageType.NONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public AdvantagePicker(@NonNull Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AdvantageType getValue() {
|
|
||||||
return mSelectedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(AdvantageType value) {
|
|
||||||
if (mSelectedValue != value) {
|
|
||||||
mSelectedValue = value;
|
|
||||||
if (mOnValueChangedListener != null) {
|
|
||||||
mOnValueChangedListener.onValueChanged(mSelectedValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final int checkedId = mHolder.group.getCheckedRadioButtonId();
|
|
||||||
if (mSelectedValue == AdvantageType.ADVANTAGE) {
|
|
||||||
if (checkedId != R.id.hasAdvantage) {
|
|
||||||
mHolder.advantage.setChecked(true);
|
|
||||||
}
|
|
||||||
} else if (mSelectedValue == AdvantageType.DISADVANTAGE) {
|
|
||||||
if (checkedId != R.id.hasDisadvantage) {
|
|
||||||
mHolder.disadvantage.setChecked(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (checkedId != R.id.none) {
|
|
||||||
mHolder.none.setChecked(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnValueChangedListener(OnValueChangedListener listener) {
|
|
||||||
mOnValueChangedListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueChangedListener {
|
|
||||||
void onValueChanged(AdvantageType value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final RadioGroup group;
|
|
||||||
final MaterialRadioButton none;
|
|
||||||
final MaterialRadioButton advantage;
|
|
||||||
final MaterialRadioButton disadvantage;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RadioGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
|
||||||
|
|
||||||
import com.google.android.material.radiobutton.MaterialRadioButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class ProficiencyPicker extends ConstraintLayout {
|
|
||||||
private final ViewHolder mHolder;
|
|
||||||
private OnValueChangedListener mOnValueChangedListener;
|
|
||||||
private ProficiencyType mSelectedValue;
|
|
||||||
|
|
||||||
public ProficiencyPicker(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
mSelectedValue = ProficiencyType.NONE;
|
|
||||||
mOnValueChangedListener = null;
|
|
||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
View root = inflater.inflate(R.layout.component_proficiency_picker, this, true);
|
|
||||||
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
setValue(ProficiencyType.NONE);
|
|
||||||
mHolder.group.setOnCheckedChangeListener((group, checkedId) -> {
|
|
||||||
if (R.id.proficient == checkedId) {
|
|
||||||
setValue(ProficiencyType.PROFICIENT);
|
|
||||||
} else if (R.id.expertise == checkedId) {
|
|
||||||
setValue(ProficiencyType.EXPERTISE);
|
|
||||||
} else {
|
|
||||||
setValue(ProficiencyType.NONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProficiencyPicker(@NonNull Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProficiencyType getValue() {
|
|
||||||
return mSelectedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(ProficiencyType value) {
|
|
||||||
if (mSelectedValue != value) {
|
|
||||||
mSelectedValue = value;
|
|
||||||
if (mOnValueChangedListener != null) {
|
|
||||||
mOnValueChangedListener.onValueChanged(mSelectedValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final int checkedId = mHolder.group.getCheckedRadioButtonId();
|
|
||||||
if (mSelectedValue == ProficiencyType.PROFICIENT) {
|
|
||||||
if (checkedId != R.id.proficient) {
|
|
||||||
mHolder.proficient.setChecked(true);
|
|
||||||
}
|
|
||||||
} else if (mSelectedValue == ProficiencyType.EXPERTISE) {
|
|
||||||
if (checkedId != R.id.expertise) {
|
|
||||||
mHolder.expertise.setChecked(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (checkedId != R.id.none) {
|
|
||||||
mHolder.none.setChecked(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnValueChangedListener(OnValueChangedListener listener) {
|
|
||||||
mOnValueChangedListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueChangedListener {
|
|
||||||
void onValueChanged(ProficiencyType value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final RadioGroup group;
|
|
||||||
final MaterialRadioButton none;
|
|
||||||
final MaterialRadioButton proficient;
|
|
||||||
final MaterialRadioButton expertise;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
group = root.findViewById(R.id.group);
|
|
||||||
none = root.findViewById(R.id.none);
|
|
||||||
proficient = root.findViewById(R.id.proficient);
|
|
||||||
expertise = root.findViewById(R.id.expertise);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.TypedArray;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class Stepper extends ConstraintLayout {
|
|
||||||
private final ViewHolder mHolder;
|
|
||||||
private int mCurrentValue;
|
|
||||||
private int mStep;
|
|
||||||
private int mMinValue;
|
|
||||||
private int mMaxValue;
|
|
||||||
private String mLabel;
|
|
||||||
private OnValueChangeListener mOnValueChangeListener;
|
|
||||||
private OnFormatValueCallback mOnFormatValueCallback;
|
|
||||||
|
|
||||||
public Stepper(@NonNull Context context, @Nullable AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
|
|
||||||
mCurrentValue = 0;
|
|
||||||
|
|
||||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Stepper, 0, 0);
|
|
||||||
mStep = a.getInt(R.styleable.Stepper_stepAmount, 1);
|
|
||||||
mMinValue = a.getInt(R.styleable.Stepper_minValue, Integer.MIN_VALUE);
|
|
||||||
mMaxValue = a.getInt(R.styleable.Stepper_maxValue, Integer.MAX_VALUE);
|
|
||||||
mLabel = a.getString(R.styleable.Stepper_label);
|
|
||||||
a.recycle();
|
|
||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
View root = inflater.inflate(R.layout.component_stepper, this, true);
|
|
||||||
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
setValue(mCurrentValue);
|
|
||||||
updateDisplayedValue();
|
|
||||||
mHolder.increment.setOnClickListener(v -> setValue(mCurrentValue + mStep));
|
|
||||||
mHolder.decrement.setOnClickListener(v -> setValue(mCurrentValue - mStep));
|
|
||||||
|
|
||||||
mHolder.label.setText(mLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stepper(Context context) {
|
|
||||||
this(context, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLabel() {
|
|
||||||
return mLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLabel(String newLabel) {
|
|
||||||
if (!Objects.equals(mLabel, newLabel)) {
|
|
||||||
mLabel = newLabel;
|
|
||||||
mHolder.label.setText(mLabel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return mCurrentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(int value) {
|
|
||||||
int oldValue = this.mCurrentValue;
|
|
||||||
int newValue = Math.min(mMaxValue, Math.max(mMinValue, value));
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnValueChangeListener(OnValueChangeListener listener) {
|
|
||||||
mOnValueChangeListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnFormatValueCallback(OnFormatValueCallback callback) {
|
|
||||||
mOnFormatValueCallback = callback;
|
|
||||||
updateDisplayedValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStep() {
|
|
||||||
return mStep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(int step) {
|
|
||||||
this.mStep = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinValue() {
|
|
||||||
return mMinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinValue(int minValue) {
|
|
||||||
this.mMinValue = minValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxValue() {
|
|
||||||
return mMaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxValue(int maxValue) {
|
|
||||||
this.mMaxValue = maxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueChangeListener {
|
|
||||||
void onChange(int value, int previousValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnFormatValueCallback {
|
|
||||||
String onFormatValue(int value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final TextView text;
|
|
||||||
final TextView label;
|
|
||||||
final Button increment;
|
|
||||||
final Button decrement;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
text = root.findViewById(R.id.text);
|
|
||||||
label = root.findViewById(R.id.label);
|
|
||||||
increment = root.findViewById(R.id.increment);
|
|
||||||
decrement = root.findViewById(R.id.decrement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.dashboard;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
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.GridLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
|
||||||
ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
mViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
setupRecyclerView(mHolder.list);
|
|
||||||
|
|
||||||
// TODO: subscribe better
|
|
||||||
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);
|
|
||||||
Context context = requireContext();
|
|
||||||
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
LiveData<List<Monster>> monsterData = mViewModel.getMonsters();
|
|
||||||
mAdapter = new DashboardRecyclerViewAdapter(monster -> {
|
|
||||||
if (monster != null) {
|
|
||||||
navigateToMonsterDetail(monster);
|
|
||||||
} else {
|
|
||||||
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (monsterData != null) {
|
|
||||||
monsterData.observe(getViewLifecycleOwner(), monsters -> mAdapter.submitList(monsters));
|
|
||||||
}
|
|
||||||
recyclerView.setAdapter(mAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void navigateToMonsterDetail(Monster monster) {
|
|
||||||
NavDirections action = DashboardFragmentDirections.actionNavigationDashboardToNavigationMonster(monster.id.toString());
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final RecyclerView list;
|
|
||||||
|
|
||||||
ViewHolder(View root) {
|
|
||||||
list = root.findViewById(R.id.list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.dashboard;
|
|
||||||
|
|
||||||
import android.text.Html;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.DiffUtil;
|
|
||||||
import androidx.recyclerview.widget.ListAdapter;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
|
||||||
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.Logger;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class DashboardRecyclerViewAdapter extends ListAdapter<Monster, DashboardRecyclerViewAdapter.ViewHolder> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areContentsTheSame(@NonNull Monster oldItem, @NonNull Monster newItem) {
|
|
||||||
return oldItem.equals(newItem);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final ItemCallback mOnClick;
|
|
||||||
|
|
||||||
protected DashboardRecyclerViewAdapter(ItemCallback onClick) {
|
|
||||||
super(DIFF_CALLBACK);
|
|
||||||
mOnClick = onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
return new ViewHolder(CardMonsterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
|
||||||
Logger.logUnimplementedMethod();
|
|
||||||
Monster monster = getItem(position);
|
|
||||||
holder.monster = monster;
|
|
||||||
holder.name.setText(monster.name);
|
|
||||||
holder.meta.setText(monster.getMeta());
|
|
||||||
holder.strengthAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.strengthSavingThrowAdvantage));
|
|
||||||
holder.strengthModifier.setText(Helpers.getModifierString(monster.getStrengthModifier()));
|
|
||||||
holder.strengthName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.STRENGTH));
|
|
||||||
holder.strengthProficiency.setText(Helpers.getProficiencyAbbreviation(monster.strengthSavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.dexterityAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.dexteritySavingThrowAdvantage));
|
|
||||||
holder.dexterityModifier.setText(Helpers.getModifierString(monster.getDexterityModifier()));
|
|
||||||
holder.dexterityName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.DEXTERITY));
|
|
||||||
holder.dexterityProficiency.setText(Helpers.getProficiencyAbbreviation(monster.dexteritySavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.constitutionAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.constitutionSavingThrowAdvantage));
|
|
||||||
holder.constitutionModifier.setText(Helpers.getModifierString(monster.getConstitutionModifier()));
|
|
||||||
holder.constitutionName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.CONSTITUTION));
|
|
||||||
holder.constitutionProficiency.setText(Helpers.getProficiencyAbbreviation(monster.constitutionSavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.intelligenceAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.intelligenceSavingThrowAdvantage));
|
|
||||||
holder.intelligenceModifier.setText(Helpers.getModifierString(monster.getIntelligenceModifier()));
|
|
||||||
holder.intelligenceName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.INTELLIGENCE));
|
|
||||||
holder.intelligenceProficiency.setText(Helpers.getProficiencyAbbreviation(monster.intelligenceSavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.wisdomAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.wisdomSavingThrowAdvantage));
|
|
||||||
holder.wisdomModifier.setText(Helpers.getModifierString(monster.getWisdomModifier()));
|
|
||||||
holder.wisdomName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.WISDOM));
|
|
||||||
holder.wisdomProficiency.setText(Helpers.getProficiencyAbbreviation(monster.wisdomSavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.charismaAdvantage.setText(Helpers.getAdvantageAbbreviation(monster.charismaSavingThrowAdvantage));
|
|
||||||
holder.charismaModifier.setText(Helpers.getModifierString(monster.getCharismaModifier()));
|
|
||||||
holder.charismaName.setText(Helpers.getAbilityScoreAbbreviation(AbilityScore.CHARISMA));
|
|
||||||
holder.charismaProficiency.setText(Helpers.getProficiencyAbbreviation(monster.charismaSavingThrowProficiency));
|
|
||||||
|
|
||||||
holder.armorClass.setText(String.valueOf(monster.getArmorClassValue()));
|
|
||||||
holder.hitPoints.setText(String.valueOf(monster.getHitPointsValue()));
|
|
||||||
holder.challengeRating.setText(holder.challengeRating.getResources().getString(R.string.label_challenge_rating_with_value, Helpers.getChallengeRatingAbbreviation(monster.challengeRating)));
|
|
||||||
|
|
||||||
int numActions = monster.actions.size();
|
|
||||||
if (numActions > 0) {
|
|
||||||
holder.action1Group.setVisibility(View.VISIBLE);
|
|
||||||
Trait action = monster.actions.get(0);
|
|
||||||
holder.action1Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description)));
|
|
||||||
holder.action1Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name)));
|
|
||||||
} else {
|
|
||||||
holder.action1Group.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numActions > 1) {
|
|
||||||
holder.action2Group.setVisibility(View.VISIBLE);
|
|
||||||
Trait action = monster.actions.get(1);
|
|
||||||
holder.action2Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description)));
|
|
||||||
holder.action2Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name)));
|
|
||||||
} else {
|
|
||||||
holder.action2Group.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numActions > 2) {
|
|
||||||
holder.action3Group.setVisibility(View.VISIBLE);
|
|
||||||
Trait action = monster.actions.get(2);
|
|
||||||
holder.action3Description.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.description)));
|
|
||||||
holder.action3Name.setText(Html.fromHtml(CommonMarkHelper.toHtml(action.name)));
|
|
||||||
} else {
|
|
||||||
holder.action3Group.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(holder.monster);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ItemCallback {
|
|
||||||
void onItemCallback(Monster monster);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
public final TextView name;
|
|
||||||
public final TextView meta;
|
|
||||||
public final View action1Group;
|
|
||||||
public final TextView action1Name;
|
|
||||||
public final TextView action1Description;
|
|
||||||
public final View action2Group;
|
|
||||||
public final TextView action2Name;
|
|
||||||
public final TextView action2Description;
|
|
||||||
public final View action3Group;
|
|
||||||
public final TextView action3Name;
|
|
||||||
public final TextView action3Description;
|
|
||||||
public final TextView strengthName;
|
|
||||||
public final TextView strengthModifier;
|
|
||||||
public final TextView strengthProficiency;
|
|
||||||
public final TextView strengthAdvantage;
|
|
||||||
public final TextView dexterityName;
|
|
||||||
public final TextView dexterityModifier;
|
|
||||||
public final TextView dexterityProficiency;
|
|
||||||
public final TextView dexterityAdvantage;
|
|
||||||
public final TextView constitutionName;
|
|
||||||
public final TextView constitutionModifier;
|
|
||||||
public final TextView constitutionProficiency;
|
|
||||||
public final TextView constitutionAdvantage;
|
|
||||||
public final TextView intelligenceName;
|
|
||||||
public final TextView intelligenceModifier;
|
|
||||||
public final TextView intelligenceProficiency;
|
|
||||||
public final TextView intelligenceAdvantage;
|
|
||||||
public final TextView wisdomName;
|
|
||||||
public final TextView wisdomModifier;
|
|
||||||
public final TextView wisdomProficiency;
|
|
||||||
public final TextView wisdomAdvantage;
|
|
||||||
public final TextView charismaName;
|
|
||||||
public final TextView charismaModifier;
|
|
||||||
public final TextView charismaProficiency;
|
|
||||||
public final TextView charismaAdvantage;
|
|
||||||
public final TextView armorClass;
|
|
||||||
public final TextView hitPoints;
|
|
||||||
public final TextView challengeRating;
|
|
||||||
public Monster monster;
|
|
||||||
|
|
||||||
public ViewHolder(@NonNull CardMonsterBinding binding) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
name = binding.name;
|
|
||||||
meta = binding.meta;
|
|
||||||
action1Group = binding.action1.getRoot();
|
|
||||||
action1Name = binding.action1.name;
|
|
||||||
action1Description = binding.action1.description;
|
|
||||||
action2Group = binding.action2.getRoot();
|
|
||||||
action2Name = binding.action2.name;
|
|
||||||
action2Description = binding.action2.description;
|
|
||||||
action3Group = binding.action3.getRoot();
|
|
||||||
action3Name = binding.action3.name;
|
|
||||||
action3Description = binding.action3.description;
|
|
||||||
strengthName = binding.strength.name;
|
|
||||||
strengthModifier = binding.strength.modifier;
|
|
||||||
strengthProficiency = binding.strength.proficiency;
|
|
||||||
strengthAdvantage = binding.strength.advantage;
|
|
||||||
dexterityName = binding.dexterity.name;
|
|
||||||
dexterityModifier = binding.dexterity.modifier;
|
|
||||||
dexterityProficiency = binding.dexterity.proficiency;
|
|
||||||
dexterityAdvantage = binding.dexterity.advantage;
|
|
||||||
constitutionName = binding.constitution.name;
|
|
||||||
constitutionModifier = binding.constitution.modifier;
|
|
||||||
constitutionProficiency = binding.constitution.proficiency;
|
|
||||||
constitutionAdvantage = binding.constitution.advantage;
|
|
||||||
intelligenceName = binding.intelligence.name;
|
|
||||||
intelligenceModifier = binding.intelligence.modifier;
|
|
||||||
intelligenceProficiency = binding.intelligence.proficiency;
|
|
||||||
intelligenceAdvantage = binding.intelligence.advantage;
|
|
||||||
wisdomName = binding.wisdom.name;
|
|
||||||
wisdomModifier = binding.wisdom.modifier;
|
|
||||||
wisdomProficiency = binding.wisdom.proficiency;
|
|
||||||
wisdomAdvantage = binding.wisdom.advantage;
|
|
||||||
charismaName = binding.charisma.name;
|
|
||||||
charismaModifier = binding.charisma.modifier;
|
|
||||||
charismaProficiency = binding.charisma.proficiency;
|
|
||||||
charismaAdvantage = binding.charisma.advantage;
|
|
||||||
armorClass = binding.armorClass.value;
|
|
||||||
hitPoints = binding.hitPoints.value;
|
|
||||||
challengeRating = binding.challengeRating;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Helpers {
|
|
||||||
@NonNull
|
|
||||||
public static String getModifierString(int value) {
|
|
||||||
return String.format(Locale.getDefault(), "%+d", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getAbilityScoreAbbreviation(@NonNull AbilityScore abilityScore) {
|
|
||||||
switch (abilityScore) {
|
|
||||||
case STRENGTH:
|
|
||||||
return "S";
|
|
||||||
case DEXTERITY:
|
|
||||||
return "D";
|
|
||||||
case CONSTITUTION:
|
|
||||||
return "C";
|
|
||||||
case INTELLIGENCE:
|
|
||||||
return "I";
|
|
||||||
case WISDOM:
|
|
||||||
return "W";
|
|
||||||
case CHARISMA:
|
|
||||||
return "Ch";
|
|
||||||
default:
|
|
||||||
Logger.logUnimplementedFeature(String.format("Get an abbreviation for AbilityScore value %s", abilityScore));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getChallengeRatingAbbreviation(@NonNull ChallengeRating challengeRating) {
|
|
||||||
Logger.logUnimplementedMethod();
|
|
||||||
switch (challengeRating) {
|
|
||||||
case CUSTOM:
|
|
||||||
return "*";
|
|
||||||
case ZERO:
|
|
||||||
return "0";
|
|
||||||
case ONE_EIGHTH:
|
|
||||||
return "1/8";
|
|
||||||
case ONE_QUARTER:
|
|
||||||
return "1/4";
|
|
||||||
case ONE_HALF:
|
|
||||||
return "1/2";
|
|
||||||
case ONE:
|
|
||||||
return "1";
|
|
||||||
case TWO:
|
|
||||||
return "2";
|
|
||||||
case THREE:
|
|
||||||
return "3";
|
|
||||||
case FOUR:
|
|
||||||
return "4";
|
|
||||||
case FIVE:
|
|
||||||
return "5";
|
|
||||||
case SIX:
|
|
||||||
return "6";
|
|
||||||
case SEVEN:
|
|
||||||
return "7";
|
|
||||||
case EIGHT:
|
|
||||||
return "8";
|
|
||||||
case NINE:
|
|
||||||
return "9";
|
|
||||||
case TEN:
|
|
||||||
return "10";
|
|
||||||
case ELEVEN:
|
|
||||||
return "11";
|
|
||||||
case TWELVE:
|
|
||||||
return "12";
|
|
||||||
case THIRTEEN:
|
|
||||||
return "13";
|
|
||||||
case FOURTEEN:
|
|
||||||
return "14";
|
|
||||||
case FIFTEEN:
|
|
||||||
return "15";
|
|
||||||
case SIXTEEN:
|
|
||||||
return "16";
|
|
||||||
case SEVENTEEN:
|
|
||||||
return "17";
|
|
||||||
case EIGHTEEN:
|
|
||||||
return "18";
|
|
||||||
case NINETEEN:
|
|
||||||
return "19";
|
|
||||||
case TWENTY:
|
|
||||||
return "20";
|
|
||||||
case TWENTY_ONE:
|
|
||||||
return "21";
|
|
||||||
case TWENTY_TWO:
|
|
||||||
return "22";
|
|
||||||
case TWENTY_THREE:
|
|
||||||
return "23";
|
|
||||||
case TWENTY_FOUR:
|
|
||||||
return "24";
|
|
||||||
case TWENTY_FIVE:
|
|
||||||
return "25";
|
|
||||||
case TWENTY_SIX:
|
|
||||||
return "26";
|
|
||||||
case TWENTY_SEVEN:
|
|
||||||
return "27";
|
|
||||||
case TWENTY_EIGHT:
|
|
||||||
return "28";
|
|
||||||
case TWENTY_NINE:
|
|
||||||
return "29";
|
|
||||||
case THIRTY:
|
|
||||||
return "30";
|
|
||||||
default:
|
|
||||||
Logger.logUnimplementedFeature(String.format("Get an abbreviation for ChallengeRating value %s", challengeRating));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getProficiencyAbbreviation(@NonNull ProficiencyType proficiency) {
|
|
||||||
switch (proficiency) {
|
|
||||||
case NONE:
|
|
||||||
return "";
|
|
||||||
case EXPERTISE:
|
|
||||||
return "E";
|
|
||||||
case PROFICIENT:
|
|
||||||
return "P";
|
|
||||||
default:
|
|
||||||
Logger.logUnimplementedFeature(String.format("Get an abbreviation for ProficiencyType value %s", proficiency));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String getAdvantageAbbreviation(@NonNull AdvantageType advantage) {
|
|
||||||
switch (advantage) {
|
|
||||||
case NONE:
|
|
||||||
return "";
|
|
||||||
case ADVANTAGE:
|
|
||||||
return "A";
|
|
||||||
case DISADVANTAGE:
|
|
||||||
return "D";
|
|
||||||
default:
|
|
||||||
Logger.logUnimplementedFeature(String.format("Get an abbreviation for AdvantageType value %s", advantage));
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.dashboard;
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DashboardViewModel extends ViewModel {
|
|
||||||
private final MutableLiveData<List<Monster>> mMonsters;
|
|
||||||
|
|
||||||
public DashboardViewModel() {
|
|
||||||
mMonsters = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<Monster>> getMonsters() {
|
|
||||||
return mMonsters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMonsters(List<Monster> monsters) {
|
|
||||||
mMonsters.setValue(monsters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
private final String ABILITY_SCORE_FORMAT = "%d (%+d)";
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
private int getModifier(int value) {
|
|
||||||
return value / 2 - 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_ability_scores, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final Stepper strength;
|
|
||||||
final Stepper dexterity;
|
|
||||||
final Stepper constitution;
|
|
||||||
final Stepper intelligence;
|
|
||||||
final Stepper wisdom;
|
|
||||||
final Stepper charisma;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ArmorType;
|
|
||||||
import com.majinnaibu.monstercards.helpers.ArrayHelper;
|
|
||||||
import com.majinnaibu.monstercards.ui.components.Stepper;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditArmorFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_armor, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.armorType.setAdapter(new ArrayAdapter<ArmorType>(requireContext(), R.layout.dropdown_list_item, ArmorType.values()) {
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
ArmorType item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
ArmorType item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getDropDownView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.armorType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
ArmorType selectedItem = (ArmorType) parent.getItemAtPosition(position);
|
|
||||||
mViewModel.setArmorType(selectedItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
mViewModel.setArmorType(ArmorType.NONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.armorType.setSelection(ArrayHelper.indexOf(ArmorType.values(), mViewModel.getArmorType().getValue()));
|
|
||||||
|
|
||||||
mHolder.naturalArmorBonus.setValue(mViewModel.getNaturalArmorBonusUnboxed());
|
|
||||||
mHolder.naturalArmorBonus.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setNaturalArmorBonus(newValue));
|
|
||||||
|
|
||||||
mHolder.hasShield.setChecked(mViewModel.getHasShieldValueAsBoolean());
|
|
||||||
mHolder.hasShield.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.setHasShield(isChecked));
|
|
||||||
|
|
||||||
mHolder.shieldBonus.setValue(mViewModel.getShieldBonusUnboxed());
|
|
||||||
mHolder.shieldBonus.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setShieldBonus(newValue));
|
|
||||||
|
|
||||||
mHolder.customArmor.setText(mViewModel.getCustomArmor().getValue());
|
|
||||||
mHolder.customArmor.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomArmor(s.toString()))));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
private final Spinner armorType;
|
|
||||||
private final Stepper naturalArmorBonus;
|
|
||||||
private final SwitchCompat hasShield;
|
|
||||||
private final Stepper shieldBonus;
|
|
||||||
private final EditText customArmor;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
armorType = root.findViewById(R.id.armorType);
|
|
||||||
naturalArmorBonus = root.findViewById(R.id.naturalArmorBonus);
|
|
||||||
hasShield = root.findViewById(R.id.hasShield);
|
|
||||||
shieldBonus = root.findViewById(R.id.shieldBonus);
|
|
||||||
customArmor = root.findViewById(R.id.customArmor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
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;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.ui.components.Stepper;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditBasicInfoFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mHolder.name.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_basic_info, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.name.setText(mViewModel.getName().getValue());
|
|
||||||
mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString())));
|
|
||||||
|
|
||||||
mHolder.size.setText(mViewModel.getSize().getValue());
|
|
||||||
mHolder.size.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setSize(s.toString())));
|
|
||||||
|
|
||||||
mHolder.type.setText(mViewModel.getType().getValue());
|
|
||||||
mHolder.type.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setType(s.toString())));
|
|
||||||
|
|
||||||
mHolder.subtype.setText(mViewModel.getSubtype().getValue());
|
|
||||||
mHolder.subtype.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setSubtype(s.toString())));
|
|
||||||
|
|
||||||
mHolder.alignment.setText(mViewModel.getAlignment().getValue());
|
|
||||||
mHolder.alignment.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setAlignment(s.toString())));
|
|
||||||
|
|
||||||
mHolder.customHitPoints.setText(mViewModel.getCustomHitPoints().getValue());
|
|
||||||
mHolder.customHitPoints.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomHitPoints(s.toString()))));
|
|
||||||
|
|
||||||
mHolder.hitDice.setValue(mViewModel.getHitDiceUnboxed());
|
|
||||||
mHolder.hitDice.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setHitDice(newValue));
|
|
||||||
|
|
||||||
mHolder.hasCustomHitPoints.setChecked(mViewModel.getHasCustomHitPointsValueAsBoolean());
|
|
||||||
mHolder.hasCustomHitPoints.setOnCheckedChangeListener((button, isChecked) -> mViewModel.setHasCustomHitPoints(isChecked));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
private final EditText name;
|
|
||||||
private final EditText size;
|
|
||||||
private final EditText type;
|
|
||||||
private final EditText subtype;
|
|
||||||
private final EditText alignment;
|
|
||||||
private final EditText customHitPoints;
|
|
||||||
private final Stepper hitDice;
|
|
||||||
private final SwitchMaterial hasCustomHitPoints;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
size = root.findViewById(R.id.size);
|
|
||||||
type = root.findViewById(R.id.type);
|
|
||||||
subtype = root.findViewById(R.id.subtype);
|
|
||||||
alignment = root.findViewById(R.id.alignment);
|
|
||||||
customHitPoints = root.findViewById(R.id.customHitPoints);
|
|
||||||
hitDice = root.findViewById(R.id.hitDice);
|
|
||||||
hasCustomHitPoints = root.findViewById(R.id.hasCustomHitPoints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ChallengeRating;
|
|
||||||
import com.majinnaibu.monstercards.helpers.ArrayHelper;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditChallengeRatingFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_challenge_rating, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.challengeRating.setAdapter(new ArrayAdapter<ChallengeRating>(requireContext(), R.layout.dropdown_list_item, ChallengeRating.values()) {
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
ChallengeRating item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
||||||
ChallengeRating item = getItem(position);
|
|
||||||
TextView view = (TextView) super.getDropDownView(position, convertView, parent);
|
|
||||||
view.setText(item.displayName);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.challengeRating.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
ChallengeRating selectedItem = (ChallengeRating) parent.getItemAtPosition(position);
|
|
||||||
mViewModel.setChallengeRating(selectedItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
|
||||||
mViewModel.setChallengeRating(ChallengeRating.CUSTOM);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mHolder.challengeRating.setSelection(ArrayHelper.indexOf(ChallengeRating.values(), mViewModel.getChallengeRating().getValue()));
|
|
||||||
|
|
||||||
mHolder.customChallengeRatingDescription.setText(mViewModel.getCustomChallengeRatingDescription().getValue());
|
|
||||||
mHolder.customChallengeRatingDescription.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomChallengeRatingDescription(s.toString()))));
|
|
||||||
|
|
||||||
mHolder.customProficiencyBonus.setText(mViewModel.getCustomProficiencyBonusValueAsString());
|
|
||||||
mHolder.customProficiencyBonus.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomProficiencyBonus(s.toString()))));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final Spinner challengeRating;
|
|
||||||
final EditText customChallengeRatingDescription;
|
|
||||||
final EditText customProficiencyBonus;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
challengeRating = root.findViewById(R.id.challengeRating);
|
|
||||||
customChallengeRatingDescription = root.findViewById(R.id.customChallengeRatingDescription);
|
|
||||||
customProficiencyBonus = root.findViewById(R.id.customProficiencyBonus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.models.Language;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditLanguageFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mEditMonsterViewModel;
|
|
||||||
private EditLanguageViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private Language mOldLanguage;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
mViewModel = new ViewModelProvider(this).get(EditLanguageViewModel.class);
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
if (arguments != null) {
|
|
||||||
EditLanguageFragmentArgs args = EditLanguageFragmentArgs.fromBundle(arguments);
|
|
||||||
mOldLanguage = new Language(args.getName(), args.getCanSpeak());
|
|
||||||
mViewModel.copyFromLanguage(mOldLanguage);
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditLanguageFragment needs arguments");
|
|
||||||
mOldLanguage = null;
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @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);
|
|
||||||
|
|
||||||
mHolder.name.setText(mViewModel.getName().getValue());
|
|
||||||
mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString())));
|
|
||||||
|
|
||||||
mHolder.canSpeak.setChecked(mViewModel.getCanSpeakValue());
|
|
||||||
mHolder.canSpeak.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.setCanSpeak(isChecked));
|
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
if (mViewModel.hasChanges()) {
|
|
||||||
mEditMonsterViewModel.replaceLanguage(mOldLanguage, mViewModel.getLanguage().getValue());
|
|
||||||
}
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mHolder.name.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
EditText name;
|
|
||||||
SwitchCompat canSpeak;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
canSpeak = root.findViewById(R.id.canSpeak);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Language;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel;
|
|
||||||
import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData;
|
|
||||||
|
|
||||||
public class EditLanguageViewModel extends ChangeTrackedViewModel {
|
|
||||||
private final ChangeTrackedLiveData<String> mName;
|
|
||||||
private final ChangeTrackedLiveData<Boolean> mCanSpeak;
|
|
||||||
private final ChangeTrackedLiveData<Language> mLanguage;
|
|
||||||
|
|
||||||
public EditLanguageViewModel() {
|
|
||||||
super();
|
|
||||||
mName = new ChangeTrackedLiveData<>("New Language", this::makeDirty);
|
|
||||||
mCanSpeak = new ChangeTrackedLiveData<>(true, this::makeDirty);
|
|
||||||
mLanguage = new ChangeTrackedLiveData<>(makeLanguage(), this::makeDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFromLanguage(@NonNull Language language) {
|
|
||||||
mName.resetValue(language.getName());
|
|
||||||
mCanSpeak.resetValue(language.getSpeaks());
|
|
||||||
makeClean();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Language> getLanguage() {
|
|
||||||
return mLanguage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
mName.setValue(name);
|
|
||||||
mLanguage.setValue(makeLanguage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Boolean> getCanSpeak() {
|
|
||||||
return mCanSpeak;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCanSpeak(boolean canSpeak) {
|
|
||||||
mCanSpeak.setValue(canSpeak);
|
|
||||||
mLanguage.setValue(makeLanguage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getCanSpeakValue(boolean defaultIfNull) {
|
|
||||||
Boolean boxedValue = mCanSpeak.getValue();
|
|
||||||
if (boxedValue == null) {
|
|
||||||
return defaultIfNull;
|
|
||||||
}
|
|
||||||
return boxedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getCanSpeakValue() {
|
|
||||||
return getCanSpeakValue(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Language makeLanguage() {
|
|
||||||
Boolean boxedValue = mCanSpeak.getValue();
|
|
||||||
boolean canSpeak = boxedValue != null && boxedValue;
|
|
||||||
return new Language(mName.getValue(), canSpeak);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.models.Language;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditLanguagesFragment extends MCFragment {
|
|
||||||
// TODO: Make the swipe to delete not happen for the header
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
private void navigateToEditLanguage(@NonNull Language language) {
|
|
||||||
NavDirections action = EditLanguagesFragmentDirections.actionEditLanguagesFragmentToEditLanguageFragment(language.getName(), language.getSpeaks());
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_languages_list, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
setupRecyclerView(mHolder.list);
|
|
||||||
setupAddLanguageButton(mHolder.addLanguage);
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
|
||||||
Context context = requireContext();
|
|
||||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
mViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> {
|
|
||||||
EditLanguagesRecyclerViewAdapter adapter = new EditLanguagesRecyclerViewAdapter(
|
|
||||||
mViewModel.getLanguagesArray(),
|
|
||||||
language -> {
|
|
||||||
if (language != null) {
|
|
||||||
navigateToEditLanguage(language);
|
|
||||||
} else {
|
|
||||||
Logger.logError("Can't navigate to EditSkill with a null skill");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mViewModel.getTelepathyRangeUnboxed(),
|
|
||||||
(value, previousValue) -> mViewModel.setTelepathyRange(value),
|
|
||||||
mViewModel.getUnderstandsButDescription().getValue(),
|
|
||||||
new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setUnderstandsButDescription(s.toString())));
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
});
|
|
||||||
|
|
||||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
|
||||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> {
|
|
||||||
if (position > 0) {
|
|
||||||
mViewModel.removeLanguage(position - 1);
|
|
||||||
}
|
|
||||||
}, null));
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddLanguageButton(@NonNull FloatingActionButton fab) {
|
|
||||||
fab.setOnClickListener(view -> {
|
|
||||||
Language newLanguage = mViewModel.addNewLanguage();
|
|
||||||
navigateToEditLanguage(newLanguage);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
RecyclerView list;
|
|
||||||
FloatingActionButton addLanguage;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
this.list = root.findViewById(R.id.list);
|
|
||||||
this.addLanguage = root.findViewById(R.id.add_language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
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 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 int mTelepathyRange;
|
|
||||||
private final String mUnderstandsBut;
|
|
||||||
private final Stepper.OnValueChangeListener mOnTelepathyRangeChanged;
|
|
||||||
private final TextWatcher mOnUnderstandsButChanged;
|
|
||||||
|
|
||||||
private final int HEADER_VIEW_TYPE = 1;
|
|
||||||
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) {
|
|
||||||
mValues = items;
|
|
||||||
mOnClick = onClick;
|
|
||||||
mTelepathyRange = telepathyRange;
|
|
||||||
mOnTelepathyRangeChanged = telepathyRangeChangedListener;
|
|
||||||
mUnderstandsBut = understandsBut;
|
|
||||||
mOnUnderstandsButChanged = understandsButChangedListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
|
|
||||||
if (holder instanceof HeaderViewHolder) {
|
|
||||||
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
|
|
||||||
headerViewHolder.telepathy.setOnFormatValueCallback(value -> String.format(Locale.getDefault(), DISTANCE_IN_FEET_FORMAT, value));
|
|
||||||
headerViewHolder.telepathy.setValue(mTelepathyRange);
|
|
||||||
headerViewHolder.telepathy.setOnValueChangeListener(mOnTelepathyRangeChanged);
|
|
||||||
headerViewHolder.understandsBut.setText(mUnderstandsBut);
|
|
||||||
headerViewHolder.understandsBut.addTextChangedListener(mOnUnderstandsButChanged);
|
|
||||||
} else if (holder instanceof ItemViewHolder) {
|
|
||||||
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
|
|
||||||
itemViewHolder.mItem = mValues.get(position - 1);
|
|
||||||
itemViewHolder.mContentView.setText(itemViewHolder.mItem.getName());
|
|
||||||
itemViewHolder.itemView.setOnClickListener(view -> {
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(itemViewHolder.mItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return mValues.size() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(int position) {
|
|
||||||
if (position == 0) {
|
|
||||||
return HEADER_VIEW_TYPE;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
|
||||||
public HeaderViewHolder(@NonNull FragmentEditLanguagesListHeaderBinding binding) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
telepathy = binding.telepathy;
|
|
||||||
understandsBut = binding.understandsBut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ItemViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
public final TextView mContentView;
|
|
||||||
public Language mItem;
|
|
||||||
|
|
||||||
public ItemViewHolder(@NonNull FragmentEditLanguagesListItemBinding binding) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
mContentView = binding.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString() + " '" + mContentView.getText() + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.StringType;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.TraitType;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.ui.monster.MonsterDetailFragmentArgs;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.observers.DisposableCompletableObserver;
|
|
||||||
import io.reactivex.rxjava3.observers.DisposableSingleObserver;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class EditMonsterFragment extends MCFragment {
|
|
||||||
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
|
||||||
@Nullable Bundle savedInstanceState) {
|
|
||||||
|
|
||||||
MonsterRepository repository = getMonsterRepository();
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
assert arguments != null;
|
|
||||||
UUID monsterId = UUID.fromString(MonsterDetailFragmentArgs.fromBundle(arguments).getMonsterId());
|
|
||||||
|
|
||||||
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_monster, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
setTitle(getString(R.string.title_editMonster_fmt, 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)) {
|
|
||||||
repository.getMonster(monsterId).toObservable()
|
|
||||||
.firstOrError()
|
|
||||||
.subscribe(new DisposableSingleObserver<Monster>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) {
|
|
||||||
mViewModel.setHasLoaded(true);
|
|
||||||
mViewModel.setHasError(false);
|
|
||||||
mViewModel.copyFromMonster(monster);
|
|
||||||
setTitle(getString(R.string.title_editMonster_fmt, monster.name));
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
|
||||||
// TODO: Show an error state.
|
|
||||||
Logger.logError(e);
|
|
||||||
mViewModel.setHasError(true);
|
|
||||||
mViewModel.setErrorMessage(e.toString());
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mHolder.basicInfoButton.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditBasicInfoFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.armorButton.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditArmorFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.speedButton.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSpeedFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.abilityScoresButton.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditAbilityScoresFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.savingThrows.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSavingThrowsFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.challengeRating.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditChallengeRatingFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.skills.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSkillsFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.senses.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.SENSE);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.conditionImmunities.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.CONDITION_IMMUNITY);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.damageImmunities.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_IMMUNITY);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.damageResistances.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_RESISTANCE);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.damageVulnerabilities.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_VULNERABILITY);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.languages.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditLanguagesFragment();
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.abilities.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.ABILITY);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.actions.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.ACTION);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.lairActions.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.LAIR_ACTION);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.legendaryActions.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.LEGENDARY_ACTION);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.reactions.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.REACTIONS);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
mHolder.regionalActions.setOnClickListener(v -> {
|
|
||||||
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.REGIONAL_ACTION);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
if (mViewModel.hasChanges()) {
|
|
||||||
View view = getView();
|
|
||||||
AlertDialog alertDialog = new AlertDialog.Builder(requireContext()).create();
|
|
||||||
alertDialog.setTitle("Unsaved Changes");
|
|
||||||
alertDialog.setMessage("Do you want to save your changes?");
|
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Save", (dialog, id) -> {
|
|
||||||
// Save the monster. Navigate up if the save is successful. Show a SnackBar if there was an error.
|
|
||||||
getMonsterRepository().saveMonster(mViewModel.buildMonster())
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
new DisposableCompletableObserver() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
|
||||||
Logger.logError("Error creating monster", e);
|
|
||||||
assert view != null;
|
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG)
|
|
||||||
.setAction("Action", null).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Discard", (dialog, id) -> {
|
|
||||||
// Navigate up ignoring unsaved changes.
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
});
|
|
||||||
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Cancel", (dialog, id) -> {
|
|
||||||
// Do nothing.
|
|
||||||
});
|
|
||||||
alertDialog.show();
|
|
||||||
} else {
|
|
||||||
// No changes so we can safely leave.
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
|
|
||||||
TextView basicInfoButton;
|
|
||||||
TextView armorButton;
|
|
||||||
TextView speedButton;
|
|
||||||
TextView abilityScoresButton;
|
|
||||||
TextView savingThrows;
|
|
||||||
TextView skills;
|
|
||||||
TextView conditionImmunities;
|
|
||||||
TextView damageImmunities;
|
|
||||||
TextView damageResistances;
|
|
||||||
TextView damageVulnerabilities;
|
|
||||||
TextView senses;
|
|
||||||
TextView languages;
|
|
||||||
TextView challengeRating;
|
|
||||||
TextView abilities;
|
|
||||||
TextView actions;
|
|
||||||
TextView reactions;
|
|
||||||
TextView legendaryActions;
|
|
||||||
TextView lairActions;
|
|
||||||
TextView regionalActions;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
basicInfoButton = root.findViewById(R.id.basicInfo);
|
|
||||||
armorButton = root.findViewById(R.id.armor);
|
|
||||||
speedButton = root.findViewById(R.id.speed);
|
|
||||||
abilityScoresButton = root.findViewById(R.id.abilityScores);
|
|
||||||
savingThrows = root.findViewById(R.id.savingThrows);
|
|
||||||
skills = root.findViewById(R.id.skills);
|
|
||||||
conditionImmunities = root.findViewById(R.id.conditionImmunities);
|
|
||||||
damageImmunities = root.findViewById(R.id.damageImmunities);
|
|
||||||
damageResistances = root.findViewById(R.id.damageResistances);
|
|
||||||
damageVulnerabilities = root.findViewById(R.id.damageVulnerabilities);
|
|
||||||
senses = root.findViewById(R.id.senses);
|
|
||||||
languages = root.findViewById(R.id.languages);
|
|
||||||
challengeRating = root.findViewById(R.id.challengeRating);
|
|
||||||
abilities = root.findViewById(R.id.abilities);
|
|
||||||
actions = root.findViewById(R.id.actions);
|
|
||||||
reactions = root.findViewById(R.id.reactions);
|
|
||||||
legendaryActions = root.findViewById(R.id.legendaryActions);
|
|
||||||
lairActions = root.findViewById(R.id.lairActions);
|
|
||||||
regionalActions = root.findViewById(R.id.regionalActions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,94 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
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 {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mViewHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_saving_throws, container, false);
|
|
||||||
mViewHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mViewHolder.strengthProficiency.setValue(mViewModel.getStrengthProficiency().getValue());
|
|
||||||
mViewHolder.strengthProficiency.setOnValueChangedListener(value -> mViewModel.setStrengthProficiency(value));
|
|
||||||
mViewHolder.strengthAdvantage.setValue(mViewModel.getStrengthAdvantage().getValue());
|
|
||||||
mViewHolder.strengthAdvantage.setOnValueChangedListener(value -> mViewModel.setStrengthAdvantage(value));
|
|
||||||
|
|
||||||
mViewHolder.dexterityProficiency.setValue(mViewModel.getDexterityProficiency().getValue());
|
|
||||||
mViewHolder.dexterityProficiency.setOnValueChangedListener(value -> mViewModel.setDexterityProficiency(value));
|
|
||||||
mViewHolder.dexterityAdvantage.setValue(mViewModel.getDexterityAdvantage().getValue());
|
|
||||||
mViewHolder.dexterityAdvantage.setOnValueChangedListener(value -> mViewModel.setDexterityAdvantage(value));
|
|
||||||
|
|
||||||
mViewHolder.constitutionProficiency.setValue(mViewModel.getConstitutionProficiency().getValue());
|
|
||||||
mViewHolder.constitutionProficiency.setOnValueChangedListener(value -> mViewModel.setConstitutionProficiency(value));
|
|
||||||
mViewHolder.constitutionAdvantage.setValue(mViewModel.getConstitutionAdvantage().getValue());
|
|
||||||
mViewHolder.constitutionAdvantage.setOnValueChangedListener(value -> mViewModel.setConstitutionAdvantage(value));
|
|
||||||
|
|
||||||
mViewHolder.intelligenceProficiency.setValue(mViewModel.getIntelligenceProficiency().getValue());
|
|
||||||
mViewHolder.intelligenceProficiency.setOnValueChangedListener(value -> mViewModel.setIntelligenceProficiency(value));
|
|
||||||
mViewHolder.intelligenceAdvantage.setValue(mViewModel.getIntelligenceAdvantage().getValue());
|
|
||||||
mViewHolder.intelligenceAdvantage.setOnValueChangedListener(value -> mViewModel.setIntelligenceAdvantage(value));
|
|
||||||
|
|
||||||
mViewHolder.wisdomProficiency.setValue(mViewModel.getWisdomProficiency().getValue());
|
|
||||||
mViewHolder.wisdomProficiency.setOnValueChangedListener(value -> mViewModel.setWisdomProficiency(value));
|
|
||||||
mViewHolder.wisdomAdvantage.setValue(mViewModel.getWisdomAdvantage().getValue());
|
|
||||||
mViewHolder.wisdomAdvantage.setOnValueChangedListener(value -> mViewModel.setWisdomAdvantage(value));
|
|
||||||
|
|
||||||
mViewHolder.charismaProficiency.setValue(mViewModel.getCharismaProficiency().getValue());
|
|
||||||
mViewHolder.charismaProficiency.setOnValueChangedListener(value -> mViewModel.setCharismaProficiency(value));
|
|
||||||
mViewHolder.charismaAdvantage.setValue(mViewModel.getCharismaAdvantage().getValue());
|
|
||||||
mViewHolder.charismaAdvantage.setOnValueChangedListener(value -> mViewModel.setCharismaAdvantage(value));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
AdvantagePicker strengthAdvantage;
|
|
||||||
ProficiencyPicker strengthProficiency;
|
|
||||||
AdvantagePicker dexterityAdvantage;
|
|
||||||
ProficiencyPicker dexterityProficiency;
|
|
||||||
AdvantagePicker constitutionAdvantage;
|
|
||||||
ProficiencyPicker constitutionProficiency;
|
|
||||||
AdvantagePicker intelligenceAdvantage;
|
|
||||||
ProficiencyPicker intelligenceProficiency;
|
|
||||||
AdvantagePicker wisdomAdvantage;
|
|
||||||
ProficiencyPicker wisdomProficiency;
|
|
||||||
AdvantagePicker charismaAdvantage;
|
|
||||||
ProficiencyPicker charismaProficiency;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
strengthAdvantage = root.findViewById(R.id.strengthAdvantage);
|
|
||||||
strengthProficiency = root.findViewById(R.id.strengthProficiency);
|
|
||||||
dexterityAdvantage = root.findViewById(R.id.dexterityAdvantage);
|
|
||||||
dexterityProficiency = root.findViewById(R.id.dexterityProficiency);
|
|
||||||
constitutionAdvantage = root.findViewById(R.id.constitutionAdvantage);
|
|
||||||
constitutionProficiency = root.findViewById(R.id.constitutionProficiency);
|
|
||||||
intelligenceAdvantage = root.findViewById(R.id.intelligenceAdvantage);
|
|
||||||
intelligenceProficiency = root.findViewById(R.id.intelligenceProficiency);
|
|
||||||
wisdomAdvantage = root.findViewById(R.id.wisdomAdvantage);
|
|
||||||
wisdomProficiency = root.findViewById(R.id.wisdomProficiency);
|
|
||||||
charismaAdvantage = root.findViewById(R.id.charismaAdvantage);
|
|
||||||
charismaProficiency = root.findViewById(R.id.charismaProficiency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.models.Skill;
|
|
||||||
import com.majinnaibu.monstercards.ui.components.AbilityScorePicker;
|
|
||||||
import com.majinnaibu.monstercards.ui.components.AdvantagePicker;
|
|
||||||
import com.majinnaibu.monstercards.ui.components.ProficiencyPicker;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditSkillFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mEditMonsterViewModel;
|
|
||||||
private EditSkillViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private Skill mOldSkill;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
mViewModel = new ViewModelProvider(this).get(EditSkillViewModel.class);
|
|
||||||
if (getArguments() != null) {
|
|
||||||
EditSkillFragmentArgs args = EditSkillFragmentArgs.fromBundle(getArguments());
|
|
||||||
mOldSkill = new Skill(args.getName(), args.getAbilityScore(), args.getAdvantage(), args.getProficiency());
|
|
||||||
mViewModel.copyFromSkill(mOldSkill);
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditSkillFragment needs arguments.");
|
|
||||||
mOldSkill = null;
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
|
||||||
@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_skill, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.abilityScore.setValue(mViewModel.getAbilityScore().getValue());
|
|
||||||
mHolder.abilityScore.setOnValueChangedListener(value -> mViewModel.setAbilityScore(value));
|
|
||||||
|
|
||||||
mHolder.advantage.setValue(mViewModel.getAdvantage().getValue());
|
|
||||||
mHolder.advantage.setOnValueChangedListener(value -> mViewModel.setAdvantage(value));
|
|
||||||
|
|
||||||
mHolder.proficiency.setValue(mViewModel.getProficiency().getValue());
|
|
||||||
mHolder.proficiency.setOnValueChangedListener(value -> mViewModel.setProficiency(value));
|
|
||||||
|
|
||||||
mHolder.name.setText(mViewModel.getName().getValue());
|
|
||||||
mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString())));
|
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
if (mViewModel.hasChanges()) {
|
|
||||||
mEditMonsterViewModel.replaceSkill(mViewModel.getSkill().getValue(), mOldSkill);
|
|
||||||
}
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mHolder.name.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
AbilityScorePicker abilityScore;
|
|
||||||
AdvantagePicker advantage;
|
|
||||||
ProficiencyPicker proficiency;
|
|
||||||
EditText name;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
abilityScore = root.findViewById(R.id.abilityScore);
|
|
||||||
advantage = root.findViewById(R.id.advantage);
|
|
||||||
proficiency = root.findViewById(R.id.proficiency);
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AbilityScore;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.AdvantageType;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.ProficiencyType;
|
|
||||||
import com.majinnaibu.monstercards.models.Skill;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel;
|
|
||||||
import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData;
|
|
||||||
|
|
||||||
public class EditSkillViewModel extends ChangeTrackedViewModel {
|
|
||||||
private final ChangeTrackedLiveData<AbilityScore> mAbilityScore;
|
|
||||||
private final ChangeTrackedLiveData<AdvantageType> mAdvantageType;
|
|
||||||
private final ChangeTrackedLiveData<ProficiencyType> mProficiencyType;
|
|
||||||
private final ChangeTrackedLiveData<String> mName;
|
|
||||||
private final ChangeTrackedLiveData<Skill> mSkill;
|
|
||||||
|
|
||||||
public EditSkillViewModel() {
|
|
||||||
super();
|
|
||||||
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);
|
|
||||||
mSkill = new ChangeTrackedLiveData<>(makeSkill(), this::makeDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFromSkill(@NonNull Skill skill) {
|
|
||||||
mAbilityScore.resetValue(skill.abilityScore);
|
|
||||||
mAdvantageType.resetValue(skill.advantageType);
|
|
||||||
mProficiencyType.resetValue(skill.proficiencyType);
|
|
||||||
mName.resetValue(skill.name);
|
|
||||||
makeClean();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Skill> getSkill() {
|
|
||||||
return mSkill;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<AbilityScore> getAbilityScore() {
|
|
||||||
return mAbilityScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAbilityScore(AbilityScore value) {
|
|
||||||
mAbilityScore.setValue(value);
|
|
||||||
mSkill.setValue(makeSkill());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<AdvantageType> getAdvantage() {
|
|
||||||
return mAdvantageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAdvantage(AdvantageType value) {
|
|
||||||
mAdvantageType.setValue(value);
|
|
||||||
mSkill.setValue(makeSkill());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<ProficiencyType> getProficiency() {
|
|
||||||
return mProficiencyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProficiency(ProficiencyType value) {
|
|
||||||
mProficiencyType.setValue(value);
|
|
||||||
mSkill.setValue(makeSkill());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String value) {
|
|
||||||
mName.setValue(value);
|
|
||||||
mSkill.setValue(makeSkill());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Skill makeSkill() {
|
|
||||||
return new Skill(mName.getValue(), mAbilityScore.getValue(), mAdvantageType.getValue(), mProficiencyType.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.models.Skill;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A fragment representing a list of Items.
|
|
||||||
*/
|
|
||||||
public class EditSkillsFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
private void navigateToEditSkill(@NonNull Skill skill) {
|
|
||||||
NavDirections action = EditSkillsFragmentDirections.actionEditSkillsFragmentToEditSkillFragment(skill.name, skill.abilityScore, skill.proficiencyType, skill.advantageType);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_skills_list, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
setupRecyclerView(mHolder.list);
|
|
||||||
setupAddSkillButton(mHolder.addSkill);
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
|
||||||
Context context = requireContext();
|
|
||||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> {
|
|
||||||
EditSkillsRecyclerViewAdapter adapter = new EditSkillsRecyclerViewAdapter(mViewModel.getSkillsArray(), skill -> {
|
|
||||||
if (skill != null) {
|
|
||||||
navigateToEditSkill(skill);
|
|
||||||
} else {
|
|
||||||
Logger.logError("Can't navigate to EditSkill with a null skill");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
});
|
|
||||||
|
|
||||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
|
||||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeSkill(position), null));
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddSkillButton(@NonNull FloatingActionButton fab) {
|
|
||||||
fab.setOnClickListener(view -> {
|
|
||||||
Skill newSkill = mViewModel.addNewSkill();
|
|
||||||
navigateToEditSkill(newSkill);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
RecyclerView list;
|
|
||||||
FloatingActionButton addSkill;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
this.list = root.findViewById(R.id.list);
|
|
||||||
this.addSkill = root.findViewById(R.id.add_skill);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
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 java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link RecyclerView.Adapter} that can display a {@link Skill}.
|
|
||||||
*/
|
|
||||||
public class EditSkillsRecyclerViewAdapter extends RecyclerView.Adapter<EditSkillsRecyclerViewAdapter.ViewHolder> {
|
|
||||||
private final List<Skill> mValues;
|
|
||||||
private final ItemCallback mOnClick;
|
|
||||||
|
|
||||||
public EditSkillsRecyclerViewAdapter(List<Skill> items, ItemCallback onClick) {
|
|
||||||
mValues = items;
|
|
||||||
mOnClick = onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
return new ViewHolder(FragmentEditSkillsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
|
||||||
holder.mItem = mValues.get(position);
|
|
||||||
holder.mContentView.setText(mValues.get(position).name);
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(holder.mItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
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) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
mContentView = binding.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString() + " '" + mContentView.getText() + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
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 {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_speed, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mHolder.baseSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setWalkSpeed(newValue));
|
|
||||||
mHolder.baseSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
|
||||||
mViewModel.getWalkSpeed().observe(getViewLifecycleOwner(), value -> mHolder.baseSpeed.setValue(value));
|
|
||||||
|
|
||||||
mHolder.burrowSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setBurrowSpeed(newValue));
|
|
||||||
mHolder.burrowSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
|
||||||
mViewModel.getBurrowSpeed().observe(getViewLifecycleOwner(), value -> mHolder.burrowSpeed.setValue(value));
|
|
||||||
|
|
||||||
mHolder.climbSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setClimbSpeed(newValue));
|
|
||||||
mHolder.climbSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
|
||||||
mViewModel.getClimbSpeed().observe(getViewLifecycleOwner(), value -> mHolder.climbSpeed.setValue(value));
|
|
||||||
|
|
||||||
mHolder.flySpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setFlySpeed(newValue));
|
|
||||||
mHolder.flySpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
|
||||||
mViewModel.getFlySpeed().observe(getViewLifecycleOwner(), value -> mHolder.flySpeed.setValue(value));
|
|
||||||
|
|
||||||
mHolder.swimSpeed.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setSwimSpeed(newValue));
|
|
||||||
mHolder.swimSpeed.setOnFormatValueCallback(value -> String.format(getString(R.string.format_distance_in_feet), value));
|
|
||||||
mViewModel.getSwimSpeed().observe(getViewLifecycleOwner(), value -> mHolder.swimSpeed.setValue(value));
|
|
||||||
|
|
||||||
mViewModel.getCanHover().observe(getViewLifecycleOwner(), value -> mHolder.canHover.setChecked(value));
|
|
||||||
mHolder.canHover.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.setCanHover(isChecked));
|
|
||||||
|
|
||||||
mViewModel.getHasCustomSpeed().observe(getViewLifecycleOwner(), value -> mHolder.hasCustomSpeed.setChecked(value));
|
|
||||||
mHolder.hasCustomSpeed.setOnCheckedChangeListener((buttonView, isChecked) -> mViewModel.setHasCustomSpeed(isChecked));
|
|
||||||
|
|
||||||
//mViewModel.getCustomSpeed().observe(getViewLifecycleOwner(), value -> mHolder.customSpeed.setText(value));
|
|
||||||
mHolder.customSpeed.setText(mViewModel.getCustomSpeed().getValue());
|
|
||||||
mHolder.customSpeed.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomSpeed(s.toString())));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
|
|
||||||
final Stepper baseSpeed;
|
|
||||||
final Stepper burrowSpeed;
|
|
||||||
final Stepper climbSpeed;
|
|
||||||
final Stepper flySpeed;
|
|
||||||
final Stepper swimSpeed;
|
|
||||||
final SwitchCompat canHover;
|
|
||||||
final SwitchCompat hasCustomSpeed;
|
|
||||||
final EditText customSpeed;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
baseSpeed = root.findViewById(R.id.baseSpeed);
|
|
||||||
burrowSpeed = root.findViewById(R.id.burrowSpeed);
|
|
||||||
climbSpeed = root.findViewById(R.id.climbSpeed);
|
|
||||||
flySpeed = root.findViewById(R.id.flySpeed);
|
|
||||||
swimSpeed = root.findViewById(R.id.swimSpeed);
|
|
||||||
canHover = root.findViewById(R.id.canHover);
|
|
||||||
hasCustomSpeed = root.findViewById(R.id.hasCustomSpeed);
|
|
||||||
customSpeed = root.findViewById(R.id.customSpeed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.StringType;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditStringFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mEditMonsterViewModel;
|
|
||||||
private EditStringViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private String mOldValue;
|
|
||||||
private StringType mStringType;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
mViewModel = new ViewModelProvider(this).get(EditStringViewModel.class);
|
|
||||||
if (getArguments() != null) {
|
|
||||||
EditStringFragmentArgs args = EditStringFragmentArgs.fromBundle(getArguments());
|
|
||||||
mOldValue = args.getValue();
|
|
||||||
mViewModel.setValue(mOldValue);
|
|
||||||
mStringType = args.getStringType();
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditStringFragment needs arguments");
|
|
||||||
mOldValue = null;
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @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_string, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
setTitle(getTitleForStringType(mStringType));
|
|
||||||
|
|
||||||
mHolder.description.setText(mViewModel.getValueAsString());
|
|
||||||
mHolder.description.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setValue(s.toString())));
|
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
if (mViewModel.hasChanges()) {
|
|
||||||
mEditMonsterViewModel.replaceString(mStringType, mOldValue, mViewModel.getValueAsString());
|
|
||||||
}
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private String getTitleForStringType(@NonNull StringType type) {
|
|
||||||
switch (type) {
|
|
||||||
case CONDITION_IMMUNITY:
|
|
||||||
return getString(R.string.title_editConditionImmunity);
|
|
||||||
case DAMAGE_IMMUNITY:
|
|
||||||
return getString(R.string.title_editDamageImmunity);
|
|
||||||
case DAMAGE_RESISTANCE:
|
|
||||||
return getString(R.string.title_editDamageResistance);
|
|
||||||
case DAMAGE_VULNERABILITY:
|
|
||||||
return getString(R.string.title_editDamageVulnerability);
|
|
||||||
case SENSE:
|
|
||||||
return getString(R.string.title_editSense);
|
|
||||||
default:
|
|
||||||
return getString(R.string.title_editString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mHolder.description.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
EditText description;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
description = root.findViewById(R.id.description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel;
|
|
||||||
import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData;
|
|
||||||
|
|
||||||
public class EditStringViewModel extends ChangeTrackedViewModel {
|
|
||||||
private final ChangeTrackedLiveData<String> mValue;
|
|
||||||
|
|
||||||
public EditStringViewModel() {
|
|
||||||
super();
|
|
||||||
mValue = new ChangeTrackedLiveData<>("", this::makeDirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getValue() {
|
|
||||||
return mValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(String value) {
|
|
||||||
mValue.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValueAsString() {
|
|
||||||
return mValue.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetValue(String value) {
|
|
||||||
makeClean();
|
|
||||||
mValue.resetValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.StringType;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EditStringsFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private StringType mStringType;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
if (arguments != null) {
|
|
||||||
EditStringsFragmentArgs args = EditStringsFragmentArgs.fromBundle(arguments);
|
|
||||||
mStringType = args.getStringType();
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditStringsFragment needs arguments");
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_strings_list, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
setTitle(getTitleForStringType(mStringType));
|
|
||||||
setupRecyclerView(mHolder.list);
|
|
||||||
setupAddButton(mHolder.addItem);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private String getTitleForStringType(StringType type) {
|
|
||||||
switch (type) {
|
|
||||||
case CONDITION_IMMUNITY:
|
|
||||||
return getString(R.string.title_editConditionImmunities);
|
|
||||||
case DAMAGE_IMMUNITY:
|
|
||||||
return getString(R.string.title_editDamageImmunities);
|
|
||||||
case DAMAGE_RESISTANCE:
|
|
||||||
return getString(R.string.title_editDamageResistances);
|
|
||||||
case DAMAGE_VULNERABILITY:
|
|
||||||
return getString(R.string.title_editDamageVulnerabilities);
|
|
||||||
case SENSE:
|
|
||||||
return getString(R.string.title_editSenses);
|
|
||||||
default:
|
|
||||||
return getString(R.string.title_editStrings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
|
||||||
Context context = requireContext();
|
|
||||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
LiveData<List<String>> stringsData = mViewModel.getStrings(mStringType);
|
|
||||||
if (stringsData != null) {
|
|
||||||
stringsData.observe(getViewLifecycleOwner(), strings -> {
|
|
||||||
EditStringsRecyclerViewAdapter adapter = new EditStringsRecyclerViewAdapter(strings, value -> {
|
|
||||||
if (value != null) {
|
|
||||||
navigateToEditString(value);
|
|
||||||
} else {
|
|
||||||
Logger.logError("Can't navigate to EditStringFragment with a null trait");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
|
||||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeString(mStringType, position), null));
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddButton(@NonNull FloatingActionButton fab) {
|
|
||||||
fab.setOnClickListener(view -> {
|
|
||||||
String newValue = mViewModel.addNewString(mStringType);
|
|
||||||
if (newValue != null) {
|
|
||||||
navigateToEditString(newValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void navigateToEditString(String value) {
|
|
||||||
NavDirections action = EditStringsFragmentDirections.actionEditStringsFragmentToEditStringFragment(mStringType, value);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
RecyclerView list;
|
|
||||||
FloatingActionButton addItem;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
list = root.findViewById(R.id.list);
|
|
||||||
addItem = root.findViewById(R.id.add_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.databinding.FragmentEditStringsListItemBinding;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter<EditStringsRecyclerViewAdapter.ViewHolder> {
|
|
||||||
private final List<String> mValues;
|
|
||||||
private final ItemCallback mOnClick;
|
|
||||||
|
|
||||||
public EditStringsRecyclerViewAdapter(List<String> items, ItemCallback onClick) {
|
|
||||||
mValues = items;
|
|
||||||
mOnClick = onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
return new ViewHolder(FragmentEditStringsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
|
||||||
holder.mItem = mValues.get(position);
|
|
||||||
holder.mContentView.setText(mValues.get(position));
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(holder.mItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
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) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
mContentView = binding.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString() + " '" + mContentView.getText() + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
|
|
||||||
import androidx.activity.OnBackPressedCallback;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.TraitType;
|
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
import com.majinnaibu.monstercards.utils.TextChangedListener;
|
|
||||||
|
|
||||||
public class EditTraitFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mEditMonsterViewModel;
|
|
||||||
private EditTraitViewModel mViewModel;
|
|
||||||
private EditTraitFragment.ViewHolder mHolder;
|
|
||||||
private Trait mOldValue;
|
|
||||||
private TraitType mTraitType;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
mViewModel = new ViewModelProvider(this).get(EditTraitViewModel.class);
|
|
||||||
if (getArguments() != null) {
|
|
||||||
EditTraitFragmentArgs args = EditTraitFragmentArgs.fromBundle(getArguments());
|
|
||||||
mOldValue = new Trait(args.getName(), args.getDescription());
|
|
||||||
mViewModel.copyFromTrait(mOldValue);
|
|
||||||
mTraitType = args.getTraitType();
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditTraitFragment needs arguments");
|
|
||||||
mOldValue = null;
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @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_trait, container, false);
|
|
||||||
mHolder = new EditTraitFragment.ViewHolder(root);
|
|
||||||
setTitle(getTitleForTraitType(mTraitType));
|
|
||||||
|
|
||||||
mHolder.name.setText(mViewModel.getNameAsString());
|
|
||||||
mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString())));
|
|
||||||
|
|
||||||
mHolder.description.setText(mViewModel.getDescriptionAsString());
|
|
||||||
mHolder.description.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setDescription(s.toString())));
|
|
||||||
|
|
||||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
||||||
@Override
|
|
||||||
public void handleOnBackPressed() {
|
|
||||||
if (mViewModel.hasChanges()) {
|
|
||||||
mEditMonsterViewModel.replaceTrait(mTraitType, mOldValue, mViewModel.getAbilityValue());
|
|
||||||
}
|
|
||||||
Navigation.findNavController(requireView()).navigateUp();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
mHolder.name.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getTitleForTraitType(TraitType type) {
|
|
||||||
switch (type) {
|
|
||||||
case ABILITY:
|
|
||||||
return getString(R.string.title_editAbility);
|
|
||||||
case ACTION:
|
|
||||||
return getString(R.string.title_editAction);
|
|
||||||
case LAIR_ACTION:
|
|
||||||
return getString(R.string.title_editLairAction);
|
|
||||||
case LEGENDARY_ACTION:
|
|
||||||
return getString(R.string.title_editLegendaryAction);
|
|
||||||
case REACTIONS:
|
|
||||||
return getString(R.string.title_editReaction);
|
|
||||||
case REGIONAL_ACTION:
|
|
||||||
return getString(R.string.title_editRegionalAction);
|
|
||||||
default:
|
|
||||||
return getString(R.string.title_editTrait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
EditText description;
|
|
||||||
EditText name;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
description = root.findViewById(R.id.description);
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel;
|
|
||||||
import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData;
|
|
||||||
|
|
||||||
public class EditTraitViewModel extends ChangeTrackedViewModel {
|
|
||||||
private final ChangeTrackedLiveData<String> mName;
|
|
||||||
private final ChangeTrackedLiveData<String> mDescription;
|
|
||||||
private final MutableLiveData<Trait> mAbility;
|
|
||||||
|
|
||||||
public EditTraitViewModel() {
|
|
||||||
super();
|
|
||||||
mName = new ChangeTrackedLiveData<>("", this::makeDirty);
|
|
||||||
mDescription = new ChangeTrackedLiveData<>("", this::makeDirty);
|
|
||||||
mAbility = new MutableLiveData<>(makeAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
mName.setValue(name);
|
|
||||||
mAbility.setValue(makeAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNameAsString() {
|
|
||||||
return mName.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDescription() {
|
|
||||||
return mDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescription(String description) {
|
|
||||||
mDescription.setValue(description);
|
|
||||||
mAbility.setValue(makeAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescriptionAsString() {
|
|
||||||
return mDescription.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Trait getAbilityValue() {
|
|
||||||
return mAbility.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void copyFromTrait(@NonNull Trait trait) {
|
|
||||||
makeClean();
|
|
||||||
mName.resetValue(trait.name);
|
|
||||||
mDescription.resetValue(trait.description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Trait makeAbility() {
|
|
||||||
return new Trait(mName.getValue(), mDescription.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavBackStackEntry;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.enums.TraitType;
|
|
||||||
import com.majinnaibu.monstercards.models.Trait;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.MCFragment;
|
|
||||||
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class EditTraitsFragment extends MCFragment {
|
|
||||||
private EditMonsterViewModel mViewModel;
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private TraitType mTraitType;
|
|
||||||
private EditTraitsRecyclerViewAdapter mAdapter;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
if (getArguments() != null) {
|
|
||||||
EditTraitsFragmentArgs args = EditTraitsFragmentArgs.fromBundle(getArguments());
|
|
||||||
mTraitType = args.getTraitType();
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("EditTraitFragment needs arguments");
|
|
||||||
}
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @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);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_edit_traits_list, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
setTitle(getTitleForTraitType(mTraitType));
|
|
||||||
setupRecyclerView(mHolder.list);
|
|
||||||
setupAddButton(mHolder.addTrait);
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private String getTitleForTraitType(TraitType type) {
|
|
||||||
switch (type) {
|
|
||||||
case ABILITY:
|
|
||||||
return getString(R.string.title_editAbilities);
|
|
||||||
case ACTION:
|
|
||||||
return getString(R.string.title_editActions);
|
|
||||||
case LAIR_ACTION:
|
|
||||||
return getString(R.string.title_editLairActions);
|
|
||||||
case LEGENDARY_ACTION:
|
|
||||||
return getString(R.string.title_editLegendaryActions);
|
|
||||||
case REACTIONS:
|
|
||||||
return getString(R.string.title_editReactions);
|
|
||||||
case REGIONAL_ACTION:
|
|
||||||
return getString(R.string.title_editRegionalActions);
|
|
||||||
default:
|
|
||||||
return getString(R.string.title_editTraits);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
|
|
||||||
Context context = requireContext();
|
|
||||||
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
|
||||||
|
|
||||||
LiveData<List<Trait>> traitData = mViewModel.getTraits(mTraitType);
|
|
||||||
mAdapter = new EditTraitsRecyclerViewAdapter(trait -> {
|
|
||||||
if (trait != null) {
|
|
||||||
navigateToEditTrait(trait);
|
|
||||||
} else {
|
|
||||||
Logger.logError("Can't navigate to EditTraitFragment with a null trait");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (traitData != null) {
|
|
||||||
traitData.observe(getViewLifecycleOwner(), traits -> mAdapter.submitList(traits));
|
|
||||||
}
|
|
||||||
recyclerView.setAdapter(mAdapter);
|
|
||||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
|
||||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeTrait(mTraitType, position), (from, to) -> mViewModel.moveTrait(mTraitType, from, to)));
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddButton(@NonNull FloatingActionButton fab) {
|
|
||||||
fab.setOnClickListener(view -> {
|
|
||||||
Trait newTrait = mViewModel.addNewTrait(mTraitType);
|
|
||||||
if (newTrait != null) {
|
|
||||||
navigateToEditTrait(newTrait);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void navigateToEditTrait(@NonNull Trait trait) {
|
|
||||||
NavDirections action = EditTraitsFragmentDirections.actionEditTraitListFragmentToEditTraitFragment(trait.description, trait.name, mTraitType);
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
RecyclerView list;
|
|
||||||
FloatingActionButton addTrait;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
list = root.findViewById(R.id.list);
|
|
||||||
addTrait = root.findViewById(R.id.add_trait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.editmonster;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
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.models.Trait;
|
|
||||||
|
|
||||||
public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraitsRecyclerViewAdapter.ViewHolder> {
|
|
||||||
private static final DiffUtil.ItemCallback<Trait> DIFF_CALLBACK = new DiffUtil.ItemCallback<Trait>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areItemsTheSame(@NonNull Trait oldItem, @NonNull Trait newItem) {
|
|
||||||
return oldItem.equals(newItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean areContentsTheSame(@NonNull Trait oldItem, @NonNull Trait newItem) {
|
|
||||||
return oldItem.equals(newItem);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private final ItemCallback mOnClick;
|
|
||||||
|
|
||||||
protected EditTraitsRecyclerViewAdapter(ItemCallback onClick) {
|
|
||||||
super(DIFF_CALLBACK);
|
|
||||||
mOnClick = onClick;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
return new ViewHolder(FragmentEditTraitsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
|
||||||
holder.mItem = getItem(position);
|
|
||||||
holder.mContentView.setText(holder.mItem.name);
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(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) {
|
|
||||||
super(binding.getRoot());
|
|
||||||
mContentView = binding.content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return super.toString() + " '" + mContentView.getText() + "'";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.library;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
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.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 io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.observers.DisposableCompletableObserver;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class LibraryFragment extends MCFragment {
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@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);
|
|
||||||
|
|
||||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
|
||||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(requireContext(), (position, direction) -> adapter.deleteItem(position), null));
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupAddMonsterButton(@NonNull FloatingActionButton fab) {
|
|
||||||
fab.setOnClickListener(view -> {
|
|
||||||
Monster monster = new Monster();
|
|
||||||
monster.name = getString(R.string.default_monster_name);
|
|
||||||
MonsterRepository repository = this.getMonsterRepository();
|
|
||||||
repository.addMonster(monster)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
new DisposableCompletableObserver() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
View view = getView();
|
|
||||||
assert view != null;
|
|
||||||
Snackbar.make(
|
|
||||||
view,
|
|
||||||
getString(R.string.snackbar_monster_created, monster.name),
|
|
||||||
Snackbar.LENGTH_LONG)
|
|
||||||
.setAction("Action", (_view) -> navigateToMonsterDetail(monster.id))
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
|
||||||
Logger.logError("Error creating monster", e);
|
|
||||||
View view = getView();
|
|
||||||
assert view != null;
|
|
||||||
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG)
|
|
||||||
.setAction("Action", null).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void navigateToMonsterDetail(@NonNull UUID monsterId) {
|
|
||||||
NavDirections action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monsterId.toString());
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
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 com.majinnaibu.monstercards.R;
|
|
||||||
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.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() {
|
|
||||||
@Override
|
|
||||||
public void onClick(@NonNull View view) {
|
|
||||||
Monster monster = (Monster) view.getTag();
|
|
||||||
if (mOnClick != null) {
|
|
||||||
mOnClick.onItemCallback(monster);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
private List<Monster> mValues;
|
|
||||||
private Disposable mDisposable;
|
|
||||||
|
|
||||||
public LibraryRecyclerViewAdapter(Context context,
|
|
||||||
Flowable<List<Monster>> itemsObservable,
|
|
||||||
ItemCallback onClick,
|
|
||||||
ItemCallback onDelete) {
|
|
||||||
mItemsObservable = itemsObservable;
|
|
||||||
mValues = new ArrayList<>();
|
|
||||||
mContext = context;
|
|
||||||
mOnDelete = onDelete;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(final @NonNull ViewHolder holder, int position) {
|
|
||||||
Monster monster = mValues.get(position);
|
|
||||||
holder.mContentView.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,256 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.monster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
|
||||||
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
|
||||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
|
||||||
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;
|
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
|
||||||
ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
MonsterRepository repository = getMonsterRepository();
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
assert arguments != null;
|
|
||||||
UUID monsterId = UUID.fromString(MonsterDetailFragmentArgs.fromBundle(arguments).getMonsterId());
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
mViewModel = new ViewModelProvider(this).get(MonsterDetailViewModel.class);
|
|
||||||
repository.getMonster(monsterId).toObservable()
|
|
||||||
.firstOrError()
|
|
||||||
.subscribe(new DisposableSingleObserver<Monster>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) {
|
|
||||||
mViewModel.setMonster(monster);
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
|
||||||
Logger.logError(e);
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
mViewModel.getMeta().observe(getViewLifecycleOwner(), mHolder.meta::setText);
|
|
||||||
mViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> setupLabeledTextView(mHolder.armorClass, armorText, R.string.label_armor_class));
|
|
||||||
mViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> setupLabeledTextView(mHolder.hitPoints, hitPoints, R.string.label_hit_points));
|
|
||||||
mViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> setupLabeledTextView(mHolder.speed, speed, R.string.label_speed));
|
|
||||||
mViewModel.getStrength().observe(getViewLifecycleOwner(), mHolder.strength::setText);
|
|
||||||
mViewModel.getDexterity().observe(getViewLifecycleOwner(), mHolder.dexterity::setText);
|
|
||||||
mViewModel.getConstitution().observe(getViewLifecycleOwner(), mHolder.constitution::setText);
|
|
||||||
mViewModel.getIntelligence().observe(getViewLifecycleOwner(), mHolder.intelligence::setText);
|
|
||||||
mViewModel.getWisdom().observe(getViewLifecycleOwner(), mHolder.wisdom::setText);
|
|
||||||
mViewModel.getCharisma().observe(getViewLifecycleOwner(), mHolder.charisma::setText);
|
|
||||||
mViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> setupOptionalTextView(mHolder.savingThrows, savingThrows, R.string.label_saving_throws));
|
|
||||||
mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> setupOptionalTextView(mHolder.skills, skills, R.string.label_skills));
|
|
||||||
mViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageVulnerabilities, damageTypes, R.string.label_damage_vulnerabilities));
|
|
||||||
mViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageResistances, damageTypes, R.string.label_damage_resistances));
|
|
||||||
mViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageImmunities, damageTypes, R.string.label_damage_immunities));
|
|
||||||
mViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> setupOptionalTextView(mHolder.conditionImmunities, conditionImmunities, R.string.label_condition_immunities));
|
|
||||||
mViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> setupOptionalTextView(mHolder.senses, senses, R.string.label_senses));
|
|
||||||
mViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> setupOptionalTextView(mHolder.languages, languages, R.string.label_languages));
|
|
||||||
mViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> setupLabeledTextView(mHolder.challenge, challengeRating, R.string.label_challenge_rating));
|
|
||||||
mViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> setupTraitList(mHolder.abilities, abilities));
|
|
||||||
mViewModel.getActions().observe(getViewLifecycleOwner(), actions -> setupTraitList(mHolder.actions, actions, mHolder.actions_label, mHolder.actions_divider));
|
|
||||||
mViewModel.getReactions().observe(getViewLifecycleOwner(), reactions -> setupTraitList(mHolder.reactions, reactions, mHolder.reactions_label, mHolder.reactions_divider));
|
|
||||||
mViewModel.getRegionalEffects().observe(getViewLifecycleOwner(), regionalEffects -> setupTraitList(mHolder.regionalEffects, regionalEffects, mHolder.regionalEffects_label, mHolder.regionalEffects_divider));
|
|
||||||
mViewModel.getLairActions().observe(getViewLifecycleOwner(), lairActions -> setupTraitList(mHolder.lairActions, lairActions, mHolder.lairActions_label, mHolder.lairActions_divider));
|
|
||||||
mViewModel.getLegendaryActions().observe(getViewLifecycleOwner(), legendaryActions -> setupTraitList(mHolder.legendaryActions, legendaryActions, mHolder.legendaryActions_label, mHolder.legendaryActions_divider));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupLabeledTextView(@NonNull TextView view, String text, int titleId) {
|
|
||||||
String title = getString(titleId);
|
|
||||||
String fullText = String.format("<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);
|
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
|
||||||
if (item.getItemId() == R.id.menu_action_edit_monster) {
|
|
||||||
UUID monsterId = mViewModel.getId().getValue();
|
|
||||||
if (monsterId != null) {
|
|
||||||
NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString());
|
|
||||||
Navigation.findNavController(requireView()).navigate(action);
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("monsterId cannot be null.");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final TextView name;
|
|
||||||
final TextView meta;
|
|
||||||
final TextView armorClass;
|
|
||||||
final TextView hitPoints;
|
|
||||||
final TextView speed;
|
|
||||||
final TextView strength;
|
|
||||||
final TextView dexterity;
|
|
||||||
final TextView constitution;
|
|
||||||
final TextView intelligence;
|
|
||||||
final TextView wisdom;
|
|
||||||
final TextView charisma;
|
|
||||||
final TextView savingThrows;
|
|
||||||
final TextView skills;
|
|
||||||
final TextView damageVulnerabilities;
|
|
||||||
final TextView damageResistances;
|
|
||||||
final TextView damageImmunities;
|
|
||||||
final TextView conditionImmunities;
|
|
||||||
final TextView senses;
|
|
||||||
final TextView languages;
|
|
||||||
final TextView challenge;
|
|
||||||
final LinearLayout abilities;
|
|
||||||
final LinearLayout actions;
|
|
||||||
final TextView actions_label;
|
|
||||||
final ImageView actions_divider;
|
|
||||||
final LinearLayout reactions;
|
|
||||||
final TextView reactions_label;
|
|
||||||
final ImageView reactions_divider;
|
|
||||||
final LinearLayout legendaryActions;
|
|
||||||
final TextView legendaryActions_label;
|
|
||||||
final ImageView legendaryActions_divider;
|
|
||||||
final LinearLayout lairActions;
|
|
||||||
final TextView lairActions_label;
|
|
||||||
final ImageView lairActions_divider;
|
|
||||||
final LinearLayout regionalEffects;
|
|
||||||
final TextView regionalEffects_label;
|
|
||||||
final ImageView regionalEffects_divider;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
meta = root.findViewById(R.id.meta);
|
|
||||||
armorClass = root.findViewById(R.id.armorClass);
|
|
||||||
hitPoints = root.findViewById(R.id.hitPoints);
|
|
||||||
speed = root.findViewById(R.id.speed);
|
|
||||||
strength = root.findViewById(R.id.strength);
|
|
||||||
dexterity = root.findViewById(R.id.dexterity);
|
|
||||||
constitution = root.findViewById(R.id.constitution);
|
|
||||||
intelligence = root.findViewById(R.id.intelligence);
|
|
||||||
wisdom = root.findViewById(R.id.wisdom);
|
|
||||||
charisma = root.findViewById(R.id.charisma);
|
|
||||||
savingThrows = root.findViewById(R.id.savingThrows);
|
|
||||||
skills = root.findViewById(R.id.skills);
|
|
||||||
damageVulnerabilities = root.findViewById(R.id.damageVulnerabilities);
|
|
||||||
damageResistances = root.findViewById(R.id.damageResistances);
|
|
||||||
damageImmunities = root.findViewById(R.id.damageImmunities);
|
|
||||||
conditionImmunities = root.findViewById(R.id.conditionImmunities);
|
|
||||||
senses = root.findViewById(R.id.senses);
|
|
||||||
languages = root.findViewById(R.id.languages);
|
|
||||||
challenge = root.findViewById(R.id.challenge);
|
|
||||||
abilities = root.findViewById(R.id.abilities);
|
|
||||||
actions = root.findViewById(R.id.actions);
|
|
||||||
actions_divider = root.findViewById(R.id.actions_divider);
|
|
||||||
actions_label = root.findViewById(R.id.actions_label);
|
|
||||||
reactions = root.findViewById(R.id.reactions);
|
|
||||||
reactions_divider = root.findViewById(R.id.reactions_divider);
|
|
||||||
reactions_label = root.findViewById(R.id.reactions_label);
|
|
||||||
legendaryActions = root.findViewById(R.id.legendaryActions);
|
|
||||||
legendaryActions_divider = root.findViewById(R.id.legendaryActions_divider);
|
|
||||||
legendaryActions_label = root.findViewById(R.id.legendaryActions_label);
|
|
||||||
lairActions = root.findViewById(R.id.lairActions);
|
|
||||||
lairActions_divider = root.findViewById(R.id.lairActions_divider);
|
|
||||||
lairActions_label = root.findViewById(R.id.lairActions_label);
|
|
||||||
regionalEffects = root.findViewById(R.id.regionalEffects);
|
|
||||||
regionalEffects_divider = root.findViewById(R.id.regionalEffects_divider);
|
|
||||||
regionalEffects_label = root.findViewById(R.id.regionalEffects_label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.monster;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class MonsterDetailViewModel extends ViewModel {
|
|
||||||
|
|
||||||
private final MutableLiveData<List<String>> mAbilities;
|
|
||||||
private final MutableLiveData<List<String>> mActions;
|
|
||||||
private final MutableLiveData<String> mArmorClass;
|
|
||||||
private final MutableLiveData<String> mChallenge;
|
|
||||||
private final MutableLiveData<String> mCharisma;
|
|
||||||
private final MutableLiveData<String> mConditionImmunities;
|
|
||||||
private final MutableLiveData<String> mConstitution;
|
|
||||||
private final MutableLiveData<String> mDamageResistances;
|
|
||||||
private final MutableLiveData<String> mDamageImmunities;
|
|
||||||
private final MutableLiveData<String> mDamageVulnerabilities;
|
|
||||||
private final MutableLiveData<String> mDexterity;
|
|
||||||
private final MutableLiveData<String> mHitPoints;
|
|
||||||
private final MutableLiveData<String> mIntelligence;
|
|
||||||
private final MutableLiveData<List<String>> mLairActions;
|
|
||||||
private final MutableLiveData<String> mLanguages;
|
|
||||||
private final MutableLiveData<List<String>> mLegendaryActions;
|
|
||||||
private final MutableLiveData<String> mMeta;
|
|
||||||
private final MutableLiveData<String> mName;
|
|
||||||
private final MutableLiveData<List<String>> mReactions;
|
|
||||||
private final MutableLiveData<List<String>> mRegionalEffects;
|
|
||||||
private final MutableLiveData<String> mSavingThrows;
|
|
||||||
private final MutableLiveData<String> mSenses;
|
|
||||||
private final MutableLiveData<String> mSkills;
|
|
||||||
private final MutableLiveData<String> mSpeed;
|
|
||||||
private final MutableLiveData<String> mStrength;
|
|
||||||
private final MutableLiveData<String> mWisdom;
|
|
||||||
private final MutableLiveData<UUID> mMonsterId;
|
|
||||||
private Monster mMonster;
|
|
||||||
|
|
||||||
public MonsterDetailViewModel() {
|
|
||||||
mMonster = null;
|
|
||||||
mAbilities = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mArmorClass = new MutableLiveData<>("");
|
|
||||||
mChallenge = new MutableLiveData<>("");
|
|
||||||
mCharisma = new MutableLiveData<>("");
|
|
||||||
mConditionImmunities = new MutableLiveData<>("");
|
|
||||||
mConstitution = new MutableLiveData<>("");
|
|
||||||
mDamageImmunities = new MutableLiveData<>("");
|
|
||||||
mDamageResistances = new MutableLiveData<>("");
|
|
||||||
mDamageVulnerabilities = new MutableLiveData<>("");
|
|
||||||
mDexterity = new MutableLiveData<>("");
|
|
||||||
mHitPoints = new MutableLiveData<>("");
|
|
||||||
mIntelligence = new MutableLiveData<>("");
|
|
||||||
mLairActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mLanguages = new MutableLiveData<>("");
|
|
||||||
mLegendaryActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mMeta = new MutableLiveData<>("");
|
|
||||||
mName = new MutableLiveData<>("");
|
|
||||||
mReactions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mRegionalEffects = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mSavingThrows = new MutableLiveData<>("");
|
|
||||||
mSenses = new MutableLiveData<>("");
|
|
||||||
mSkills = new MutableLiveData<>("");
|
|
||||||
mSpeed = new MutableLiveData<>("");
|
|
||||||
mStrength = new MutableLiveData<>("");
|
|
||||||
mWisdom = new MutableLiveData<>("");
|
|
||||||
mMonsterId = new MutableLiveData<>(UUID.fromString("00000000-0000-0000-0000-000000000000"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getAbilities() {
|
|
||||||
return mAbilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getActions() {
|
|
||||||
return mActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getReactions() {
|
|
||||||
return mReactions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getLegendaryActions() {
|
|
||||||
return mLegendaryActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getLairActions() {
|
|
||||||
return mLairActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getRegionalEffects() {
|
|
||||||
return mRegionalEffects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getArmorClass() {
|
|
||||||
return mArmorClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getChallenge() {
|
|
||||||
return mChallenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getCharisma() {
|
|
||||||
return mCharisma;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getConditionImmunities() {
|
|
||||||
return mConditionImmunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getConstitution() {
|
|
||||||
return mConstitution;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageResistances() {
|
|
||||||
return mDamageResistances;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageImmunities() {
|
|
||||||
return mDamageImmunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageVulnerabilities() {
|
|
||||||
return mDamageVulnerabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDexterity() {
|
|
||||||
return mDexterity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getHitPoints() {
|
|
||||||
return mHitPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getIntelligence() {
|
|
||||||
return mIntelligence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getLanguages() {
|
|
||||||
return mLanguages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getMeta() {
|
|
||||||
return mMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSavingThrows() {
|
|
||||||
return mSavingThrows;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSenses() {
|
|
||||||
return mSenses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSkills() {
|
|
||||||
return mSkills;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSpeed() {
|
|
||||||
return mSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getStrength() {
|
|
||||||
return mStrength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getWisdom() {
|
|
||||||
return mWisdom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<UUID> getId() {
|
|
||||||
return mMonsterId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMonster(@NonNull Monster monster) {
|
|
||||||
mMonster = monster;
|
|
||||||
mAbilities.setValue(mMonster.getAbilityDescriptions());
|
|
||||||
mActions.setValue(mMonster.getActionDescriptions());
|
|
||||||
mArmorClass.setValue(mMonster.getArmorClass());
|
|
||||||
mChallenge.setValue(mMonster.getChallengeRatingDescription());
|
|
||||||
mCharisma.setValue(monster.getCharismaDescription());
|
|
||||||
mConditionImmunities.setValue(mMonster.getConditionImmunitiesDescription());
|
|
||||||
mConstitution.setValue(monster.getConstitutionDescription());
|
|
||||||
mDamageImmunities.setValue(mMonster.getDamageImmunitiesDescription());
|
|
||||||
mDamageResistances.setValue(mMonster.getDamageResistancesDescription());
|
|
||||||
mDamageVulnerabilities.setValue(mMonster.getDamageVulnerabilitiesDescription());
|
|
||||||
mDexterity.setValue(monster.getDexterityDescription());
|
|
||||||
mHitPoints.setValue(mMonster.getHitPoints());
|
|
||||||
mIntelligence.setValue(monster.getIntelligenceDescription());
|
|
||||||
mLairActions.setValue(mMonster.getLairActionDescriptions());
|
|
||||||
mLanguages.setValue(mMonster.getLanguagesDescription());
|
|
||||||
mLegendaryActions.setValue(mMonster.getLegendaryActionDescriptions());
|
|
||||||
mMeta.setValue(mMonster.getMeta());
|
|
||||||
mMonsterId.setValue(mMonster.id);
|
|
||||||
mName.setValue(mMonster.name);
|
|
||||||
mReactions.setValue(monster.getReactionDescriptions());
|
|
||||||
mRegionalEffects.setValue(monster.getRegionalActionDescriptions());
|
|
||||||
mSavingThrows.setValue(monster.getSavingThrowsDescription());
|
|
||||||
mSenses.setValue(monster.getSensesDescription());
|
|
||||||
mSkills.setValue(monster.getSkillsDescription());
|
|
||||||
mSpeed.setValue(mMonster.getSpeedText());
|
|
||||||
mStrength.setValue(monster.getStrengthDescription());
|
|
||||||
mWisdom.setValue(monster.getWisdomDescription());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.monster;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.TypedValue;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
|
||||||
import androidx.navigation.NavController;
|
|
||||||
import androidx.navigation.NavDirections;
|
|
||||||
import androidx.navigation.Navigation;
|
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
|
||||||
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
|
||||||
import com.majinnaibu.monstercards.helpers.CommonMarkHelper;
|
|
||||||
import com.majinnaibu.monstercards.helpers.MonsterImportHelper;
|
|
||||||
import com.majinnaibu.monstercards.helpers.StringHelper;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.ui.library.LibraryFragmentDirections;
|
|
||||||
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.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.observers.DisposableCompletableObserver;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class MonsterImportFragment extends MCFragment {
|
|
||||||
private ViewHolder mHolder;
|
|
||||||
private MonsterImportViewModel mViewModel;
|
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
Logger.logDebug("MonsterCards: loading monster for import");
|
|
||||||
Bundle arguments = getArguments();
|
|
||||||
assert arguments != null;
|
|
||||||
String json = MonsterImportFragmentArgs.fromBundle(arguments).getJson();
|
|
||||||
setHasOptionsMenu(true);
|
|
||||||
Monster monster = MonsterImportHelper.fromJSON(json);
|
|
||||||
mViewModel = new ViewModelProvider(this).get(MonsterImportViewModel.class);
|
|
||||||
mViewModel.setMonster(monster);
|
|
||||||
View root = inflater.inflate(R.layout.fragment_monster, container, false);
|
|
||||||
mHolder = new ViewHolder(root);
|
|
||||||
|
|
||||||
mViewModel.getName().observe(getViewLifecycleOwner(), mHolder.name::setText);
|
|
||||||
mViewModel.getMeta().observe(getViewLifecycleOwner(), mHolder.meta::setText);
|
|
||||||
mViewModel.getArmorClass().observe(getViewLifecycleOwner(), armorText -> setupLabeledTextView(mHolder.armorClass, armorText, R.string.label_armor_class));
|
|
||||||
mViewModel.getHitPoints().observe(getViewLifecycleOwner(), hitPoints -> setupLabeledTextView(mHolder.hitPoints, hitPoints, R.string.label_hit_points));
|
|
||||||
mViewModel.getSpeed().observe(getViewLifecycleOwner(), speed -> setupLabeledTextView(mHolder.speed, speed, R.string.label_speed));
|
|
||||||
mViewModel.getStrength().observe(getViewLifecycleOwner(), mHolder.strength::setText);
|
|
||||||
mViewModel.getDexterity().observe(getViewLifecycleOwner(), mHolder.dexterity::setText);
|
|
||||||
mViewModel.getConstitution().observe(getViewLifecycleOwner(), mHolder.constitution::setText);
|
|
||||||
mViewModel.getIntelligence().observe(getViewLifecycleOwner(), mHolder.intelligence::setText);
|
|
||||||
mViewModel.getWisdom().observe(getViewLifecycleOwner(), mHolder.wisdom::setText);
|
|
||||||
mViewModel.getCharisma().observe(getViewLifecycleOwner(), mHolder.charisma::setText);
|
|
||||||
mViewModel.getSavingThrows().observe(getViewLifecycleOwner(), savingThrows -> setupOptionalTextView(mHolder.savingThrows, savingThrows, R.string.label_saving_throws));
|
|
||||||
mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> setupOptionalTextView(mHolder.skills, skills, R.string.label_skills));
|
|
||||||
mViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageVulnerabilities, damageTypes, R.string.label_damage_vulnerabilities));
|
|
||||||
mViewModel.getDamageResistances().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageResistances, damageTypes, R.string.label_damage_resistances));
|
|
||||||
mViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), damageTypes -> setupOptionalTextView(mHolder.damageImmunities, damageTypes, R.string.label_damage_immunities));
|
|
||||||
mViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> setupOptionalTextView(mHolder.conditionImmunities, conditionImmunities, R.string.label_condition_immunities));
|
|
||||||
mViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> setupOptionalTextView(mHolder.senses, senses, R.string.label_senses));
|
|
||||||
mViewModel.getLanguages().observe(getViewLifecycleOwner(), languages -> setupOptionalTextView(mHolder.languages, languages, R.string.label_languages));
|
|
||||||
mViewModel.getChallenge().observe(getViewLifecycleOwner(), challengeRating -> setupLabeledTextView(mHolder.challenge, challengeRating, R.string.label_challenge_rating));
|
|
||||||
mViewModel.getAbilities().observe(getViewLifecycleOwner(), abilities -> setupTraitList(mHolder.abilities, abilities));
|
|
||||||
mViewModel.getActions().observe(getViewLifecycleOwner(), actions -> setupTraitList(mHolder.actions, actions, mHolder.actions_label, mHolder.actions_divider));
|
|
||||||
mViewModel.getReactions().observe(getViewLifecycleOwner(), reactions -> setupTraitList(mHolder.reactions, reactions, mHolder.reactions_label, mHolder.reactions_divider));
|
|
||||||
mViewModel.getRegionalEffects().observe(getViewLifecycleOwner(), regionalEffects -> setupTraitList(mHolder.regionalEffects, regionalEffects, mHolder.regionalEffects_label, mHolder.regionalEffects_divider));
|
|
||||||
mViewModel.getLairActions().observe(getViewLifecycleOwner(), lairActions -> setupTraitList(mHolder.lairActions, lairActions, mHolder.lairActions_label, mHolder.lairActions_divider));
|
|
||||||
mViewModel.getLegendaryActions().observe(getViewLifecycleOwner(), legendaryActions -> setupTraitList(mHolder.legendaryActions, legendaryActions, mHolder.legendaryActions_label, mHolder.legendaryActions_divider));
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupLabeledTextView(@NonNull TextView view, String text, int titleId) {
|
|
||||||
String title = getString(titleId);
|
|
||||||
String fullText = String.format("<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.import_monster, menu);
|
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
|
||||||
if (item.getItemId() == R.id.menu_action_import_monster) {
|
|
||||||
Logger.logDebug("Menu Item Selected");
|
|
||||||
Monster monster = mViewModel.getMonster();
|
|
||||||
if (monster != null) {
|
|
||||||
monster.id = UUID.randomUUID();
|
|
||||||
MonsterCardsApplication application = (MonsterCardsApplication) getApplication();
|
|
||||||
MonsterRepository repository = application.getMonsterRepository();
|
|
||||||
repository.addMonster(monster).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new DisposableCompletableObserver() {
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
Snackbar.make(
|
|
||||||
mHolder.root,
|
|
||||||
getString(R.string.snackbar_monster_created, monster.name),
|
|
||||||
Snackbar.LENGTH_LONG)
|
|
||||||
.setAction("Action", (_view) -> navigateToEditMonster(monster.id))
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
|
|
||||||
Logger.logError("Error creating monster", e);
|
|
||||||
Snackbar.make(mHolder.root, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Logger.logWTF("monsterId cannot be null.");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void navigateToEditMonster(@NonNull UUID monsterId) {
|
|
||||||
NavController navController = Navigation.findNavController(requireView());
|
|
||||||
NavDirections action;
|
|
||||||
action = MonsterImportFragmentDirections.actionMonsterImportFragmentToNavigationLibrary();
|
|
||||||
navController.navigate(action);
|
|
||||||
action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monsterId.toString());
|
|
||||||
navController.navigate(action);
|
|
||||||
action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString());
|
|
||||||
navController.navigate(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder {
|
|
||||||
final View root;
|
|
||||||
final TextView name;
|
|
||||||
final TextView meta;
|
|
||||||
final TextView armorClass;
|
|
||||||
final TextView hitPoints;
|
|
||||||
final TextView speed;
|
|
||||||
final TextView strength;
|
|
||||||
final TextView dexterity;
|
|
||||||
final TextView constitution;
|
|
||||||
final TextView intelligence;
|
|
||||||
final TextView wisdom;
|
|
||||||
final TextView charisma;
|
|
||||||
final TextView savingThrows;
|
|
||||||
final TextView skills;
|
|
||||||
final TextView damageVulnerabilities;
|
|
||||||
final TextView damageResistances;
|
|
||||||
final TextView damageImmunities;
|
|
||||||
final TextView conditionImmunities;
|
|
||||||
final TextView senses;
|
|
||||||
final TextView languages;
|
|
||||||
final TextView challenge;
|
|
||||||
final LinearLayout abilities;
|
|
||||||
final LinearLayout actions;
|
|
||||||
final TextView actions_label;
|
|
||||||
final ImageView actions_divider;
|
|
||||||
final LinearLayout reactions;
|
|
||||||
final TextView reactions_label;
|
|
||||||
final ImageView reactions_divider;
|
|
||||||
final LinearLayout legendaryActions;
|
|
||||||
final TextView legendaryActions_label;
|
|
||||||
final ImageView legendaryActions_divider;
|
|
||||||
final LinearLayout lairActions;
|
|
||||||
final TextView lairActions_label;
|
|
||||||
final ImageView lairActions_divider;
|
|
||||||
final LinearLayout regionalEffects;
|
|
||||||
final TextView regionalEffects_label;
|
|
||||||
final ImageView regionalEffects_divider;
|
|
||||||
|
|
||||||
ViewHolder(@NonNull View root) {
|
|
||||||
this.root = root;
|
|
||||||
name = root.findViewById(R.id.name);
|
|
||||||
meta = root.findViewById(R.id.meta);
|
|
||||||
armorClass = root.findViewById(R.id.armorClass);
|
|
||||||
hitPoints = root.findViewById(R.id.hitPoints);
|
|
||||||
speed = root.findViewById(R.id.speed);
|
|
||||||
strength = root.findViewById(R.id.strength);
|
|
||||||
dexterity = root.findViewById(R.id.dexterity);
|
|
||||||
constitution = root.findViewById(R.id.constitution);
|
|
||||||
intelligence = root.findViewById(R.id.intelligence);
|
|
||||||
wisdom = root.findViewById(R.id.wisdom);
|
|
||||||
charisma = root.findViewById(R.id.charisma);
|
|
||||||
savingThrows = root.findViewById(R.id.savingThrows);
|
|
||||||
skills = root.findViewById(R.id.skills);
|
|
||||||
damageVulnerabilities = root.findViewById(R.id.damageVulnerabilities);
|
|
||||||
damageResistances = root.findViewById(R.id.damageResistances);
|
|
||||||
damageImmunities = root.findViewById(R.id.damageImmunities);
|
|
||||||
conditionImmunities = root.findViewById(R.id.conditionImmunities);
|
|
||||||
senses = root.findViewById(R.id.senses);
|
|
||||||
languages = root.findViewById(R.id.languages);
|
|
||||||
challenge = root.findViewById(R.id.challenge);
|
|
||||||
abilities = root.findViewById(R.id.abilities);
|
|
||||||
actions = root.findViewById(R.id.actions);
|
|
||||||
actions_divider = root.findViewById(R.id.actions_divider);
|
|
||||||
actions_label = root.findViewById(R.id.actions_label);
|
|
||||||
reactions = root.findViewById(R.id.reactions);
|
|
||||||
reactions_divider = root.findViewById(R.id.reactions_divider);
|
|
||||||
reactions_label = root.findViewById(R.id.reactions_label);
|
|
||||||
legendaryActions = root.findViewById(R.id.legendaryActions);
|
|
||||||
legendaryActions_divider = root.findViewById(R.id.legendaryActions_divider);
|
|
||||||
legendaryActions_label = root.findViewById(R.id.legendaryActions_label);
|
|
||||||
lairActions = root.findViewById(R.id.lairActions);
|
|
||||||
lairActions_divider = root.findViewById(R.id.lairActions_divider);
|
|
||||||
lairActions_label = root.findViewById(R.id.lairActions_label);
|
|
||||||
regionalEffects = root.findViewById(R.id.regionalEffects);
|
|
||||||
regionalEffects_divider = root.findViewById(R.id.regionalEffects_divider);
|
|
||||||
regionalEffects_label = root.findViewById(R.id.regionalEffects_label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.monster;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.lifecycle.LiveData;
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class MonsterImportViewModel extends ViewModel {
|
|
||||||
private final MutableLiveData<List<String>> mAbilities;
|
|
||||||
private final MutableLiveData<List<String>> mActions;
|
|
||||||
private final MutableLiveData<String> mArmorClass;
|
|
||||||
private final MutableLiveData<String> mChallenge;
|
|
||||||
private final MutableLiveData<String> mCharisma;
|
|
||||||
private final MutableLiveData<String> mConditionImmunities;
|
|
||||||
private final MutableLiveData<String> mConstitution;
|
|
||||||
private final MutableLiveData<String> mDamageResistances;
|
|
||||||
private final MutableLiveData<String> mDamageImmunities;
|
|
||||||
private final MutableLiveData<String> mDamageVulnerabilities;
|
|
||||||
private final MutableLiveData<String> mDexterity;
|
|
||||||
private final MutableLiveData<String> mHitPoints;
|
|
||||||
private final MutableLiveData<String> mIntelligence;
|
|
||||||
private final MutableLiveData<List<String>> mLairActions;
|
|
||||||
private final MutableLiveData<String> mLanguages;
|
|
||||||
private final MutableLiveData<List<String>> mLegendaryActions;
|
|
||||||
private final MutableLiveData<String> mMeta;
|
|
||||||
private final MutableLiveData<String> mName;
|
|
||||||
private final MutableLiveData<List<String>> mReactions;
|
|
||||||
private final MutableLiveData<List<String>> mRegionalEffects;
|
|
||||||
private final MutableLiveData<String> mSavingThrows;
|
|
||||||
private final MutableLiveData<String> mSenses;
|
|
||||||
private final MutableLiveData<String> mSkills;
|
|
||||||
private final MutableLiveData<String> mSpeed;
|
|
||||||
private final MutableLiveData<String> mStrength;
|
|
||||||
private final MutableLiveData<String> mWisdom;
|
|
||||||
private final MutableLiveData<UUID> mMonsterId;
|
|
||||||
private Monster mMonster;
|
|
||||||
|
|
||||||
public MonsterImportViewModel() {
|
|
||||||
mMonster = null;
|
|
||||||
mAbilities = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mArmorClass = new MutableLiveData<>("");
|
|
||||||
mChallenge = new MutableLiveData<>("");
|
|
||||||
mCharisma = new MutableLiveData<>("");
|
|
||||||
mConditionImmunities = new MutableLiveData<>("");
|
|
||||||
mConstitution = new MutableLiveData<>("");
|
|
||||||
mDamageImmunities = new MutableLiveData<>("");
|
|
||||||
mDamageResistances = new MutableLiveData<>("");
|
|
||||||
mDamageVulnerabilities = new MutableLiveData<>("");
|
|
||||||
mDexterity = new MutableLiveData<>("");
|
|
||||||
mHitPoints = new MutableLiveData<>("");
|
|
||||||
mIntelligence = new MutableLiveData<>("");
|
|
||||||
mLairActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mLanguages = new MutableLiveData<>("");
|
|
||||||
mLegendaryActions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mMeta = new MutableLiveData<>("");
|
|
||||||
mName = new MutableLiveData<>("");
|
|
||||||
mReactions = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mRegionalEffects = new MutableLiveData<>(new ArrayList<>());
|
|
||||||
mSavingThrows = new MutableLiveData<>("");
|
|
||||||
mSenses = new MutableLiveData<>("");
|
|
||||||
mSkills = new MutableLiveData<>("");
|
|
||||||
mSpeed = new MutableLiveData<>("");
|
|
||||||
mStrength = new MutableLiveData<>("");
|
|
||||||
mWisdom = new MutableLiveData<>("");
|
|
||||||
mMonsterId = new MutableLiveData<>(UUID.fromString("00000000-0000-0000-0000-000000000000"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getAbilities() {
|
|
||||||
return mAbilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getActions() {
|
|
||||||
return mActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getReactions() {
|
|
||||||
return mReactions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getLegendaryActions() {
|
|
||||||
return mLegendaryActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getLairActions() {
|
|
||||||
return mLairActions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<List<String>> getRegionalEffects() {
|
|
||||||
return mRegionalEffects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getArmorClass() {
|
|
||||||
return mArmorClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getChallenge() {
|
|
||||||
return mChallenge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getCharisma() {
|
|
||||||
return mCharisma;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getConditionImmunities() {
|
|
||||||
return mConditionImmunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getConstitution() {
|
|
||||||
return mConstitution;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageResistances() {
|
|
||||||
return mDamageResistances;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageImmunities() {
|
|
||||||
return mDamageImmunities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDamageVulnerabilities() {
|
|
||||||
return mDamageVulnerabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getDexterity() {
|
|
||||||
return mDexterity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getHitPoints() {
|
|
||||||
return mHitPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getIntelligence() {
|
|
||||||
return mIntelligence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getLanguages() {
|
|
||||||
return mLanguages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getMeta() {
|
|
||||||
return mMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getName() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSavingThrows() {
|
|
||||||
return mSavingThrows;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSenses() {
|
|
||||||
return mSenses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSkills() {
|
|
||||||
return mSkills;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getSpeed() {
|
|
||||||
return mSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getStrength() {
|
|
||||||
return mStrength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<String> getWisdom() {
|
|
||||||
return mWisdom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<UUID> getId() {
|
|
||||||
return mMonsterId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Monster getMonster() {
|
|
||||||
return mMonster;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMonster(@NonNull Monster monster) {
|
|
||||||
mMonster = monster;
|
|
||||||
mAbilities.setValue(mMonster.getAbilityDescriptions());
|
|
||||||
mActions.setValue(mMonster.getActionDescriptions());
|
|
||||||
mArmorClass.setValue(mMonster.getArmorClass());
|
|
||||||
mChallenge.setValue(mMonster.getChallengeRatingDescription());
|
|
||||||
mCharisma.setValue(monster.getCharismaDescription());
|
|
||||||
mConditionImmunities.setValue(mMonster.getConditionImmunitiesDescription());
|
|
||||||
mConstitution.setValue(monster.getConstitutionDescription());
|
|
||||||
mDamageImmunities.setValue(mMonster.getDamageImmunitiesDescription());
|
|
||||||
mDamageResistances.setValue(mMonster.getDamageResistancesDescription());
|
|
||||||
mDamageVulnerabilities.setValue(mMonster.getDamageVulnerabilitiesDescription());
|
|
||||||
mDexterity.setValue(monster.getDexterityDescription());
|
|
||||||
mHitPoints.setValue(mMonster.getHitPoints());
|
|
||||||
mIntelligence.setValue(monster.getIntelligenceDescription());
|
|
||||||
mLairActions.setValue(mMonster.getLairActionDescriptions());
|
|
||||||
mLanguages.setValue(mMonster.getLanguagesDescription());
|
|
||||||
mLegendaryActions.setValue(mMonster.getLegendaryActionDescriptions());
|
|
||||||
mMeta.setValue(mMonster.getMeta());
|
|
||||||
mMonsterId.setValue(mMonster.id);
|
|
||||||
mName.setValue(mMonster.name);
|
|
||||||
mReactions.setValue(monster.getReactionDescriptions());
|
|
||||||
mRegionalEffects.setValue(monster.getRegionalActionDescriptions());
|
|
||||||
mSavingThrows.setValue(monster.getSavingThrowsDescription());
|
|
||||||
mSenses.setValue(monster.getSensesDescription());
|
|
||||||
mSkills.setValue(monster.getSkillsDescription());
|
|
||||||
mSpeed.setValue(mMonster.getSpeedText());
|
|
||||||
mStrength.setValue(monster.getStrengthDescription());
|
|
||||||
mWisdom.setValue(monster.getWisdomDescription());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.search;
|
|
||||||
|
|
||||||
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.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
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.ui.shared.MCFragment;
|
|
||||||
|
|
||||||
public class SearchFragment extends MCFragment {
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
final TextView textView = root.findViewById(R.id.search_query);
|
|
||||||
textView.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable editable) {
|
|
||||||
adapter.doSearch(textView.getText().toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupRecyclerView(@NonNull RecyclerView recyclerView, @NonNull SearchResultsRecyclerViewAdapter adapter) {
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
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 com.majinnaibu.monstercards.R;
|
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
|
||||||
import com.majinnaibu.monstercards.models.Monster;
|
|
||||||
import com.majinnaibu.monstercards.utils.Logger;
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
mSearchText = searchText;
|
|
||||||
Flowable<List<Monster>> foundMonsters = mRepository.searchMonsters(mSearchText);
|
|
||||||
mSubscriptionHandler = foundMonsters.subscribe(monsters -> {
|
|
||||||
mValues = monsters;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
},
|
|
||||||
throwable -> Logger.logError("Error performing search", throwable));
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
|
||||||
Monster monster = mValues.get(position);
|
|
||||||
holder.mContentView.setText(monster.name);
|
|
||||||
holder.itemView.setTag(monster);
|
|
||||||
holder.itemView.setOnClickListener(view -> {
|
|
||||||
if (mOnClickHandler != null) {
|
|
||||||
mOnClickHandler.onItem(monster);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.shared;
|
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.lifecycle.ViewModel;
|
|
||||||
|
|
||||||
public class ChangeTrackedViewModel extends ViewModel {
|
|
||||||
private final MutableLiveData<Boolean> mHasChanges;
|
|
||||||
|
|
||||||
public ChangeTrackedViewModel() {
|
|
||||||
mHasChanges = new MutableLiveData<>(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasChanges() {
|
|
||||||
Boolean value = mHasChanges.getValue();
|
|
||||||
return value != null && value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void makeDirty() {
|
|
||||||
mHasChanges.setValue(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void makeClean() {
|
|
||||||
mHasChanges.setValue(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.shared;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.MonsterCardsApplication;
|
|
||||||
import com.majinnaibu.monstercards.data.MonsterRepository;
|
|
||||||
|
|
||||||
public class MCFragment extends Fragment {
|
|
||||||
public MonsterCardsApplication getApplication() {
|
|
||||||
return (MonsterCardsApplication) requireActivity().getApplication();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MonsterRepository getMonsterRepository() {
|
|
||||||
return this.getApplication().getMonsterRepository();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AppCompatActivity requireAppCompatActivity() {
|
|
||||||
return (AppCompatActivity) requireActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTitle(CharSequence title) {
|
|
||||||
Activity activity = requireActivity();
|
|
||||||
if (activity instanceof AppCompatActivity) {
|
|
||||||
AppCompatActivity appCompatActivity = (AppCompatActivity) activity;
|
|
||||||
ActionBar supportActionBar = appCompatActivity.getSupportActionBar();
|
|
||||||
if (supportActionBar != null) {
|
|
||||||
supportActionBar.setTitle(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.ui.shared;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.PorterDuff;
|
|
||||||
import android.graphics.PorterDuffXfermode;
|
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.majinnaibu.monstercards.R;
|
|
||||||
|
|
||||||
public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
|
||||||
|
|
||||||
private final Drawable icon;
|
|
||||||
private final ColorDrawable background;
|
|
||||||
private final Paint clearPaint;
|
|
||||||
private final OnSwipeCallback mOnDelete;
|
|
||||||
private final OnMoveCallback mOnMove;
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
public SwipeToDeleteCallback(@NonNull Context context, OnSwipeCallback onDelete, OnMoveCallback onMove) {
|
|
||||||
super(onMove == null ? 0 : ItemTouchHelper.UP | ItemTouchHelper.DOWN, onDelete == null ? 0 : ItemTouchHelper.LEFT);
|
|
||||||
mOnDelete = onDelete;
|
|
||||||
mOnMove = onMove;
|
|
||||||
mContext = context;
|
|
||||||
icon = ContextCompat.getDrawable(mContext, R.drawable.ic_delete_white_36);
|
|
||||||
background = new ColorDrawable(context.getResources().getColor(R.color.red));
|
|
||||||
clearPaint = new Paint();
|
|
||||||
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMove(
|
|
||||||
@NonNull RecyclerView recyclerView,
|
|
||||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
|
||||||
@NonNull RecyclerView.ViewHolder target
|
|
||||||
) {
|
|
||||||
if (mOnMove != null) {
|
|
||||||
int from = viewHolder.getAdapterPosition();
|
|
||||||
int to = target.getAdapterPosition();
|
|
||||||
return mOnMove.onMove(from, to);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
|
||||||
if (mOnDelete != null) {
|
|
||||||
int position = viewHolder.getAdapterPosition();
|
|
||||||
mOnDelete.onSwipe(position, direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
|
||||||
View itemView = viewHolder.itemView;
|
|
||||||
int itemHeight = itemView.getBottom() - itemView.getTop();
|
|
||||||
boolean isCancelled = dX == 0 && !isCurrentlyActive;
|
|
||||||
|
|
||||||
if (isCancelled) {
|
|
||||||
c.drawRect(itemView.getRight() + dX, itemView.getTop(), itemView.getRight(), itemView.getBottom(), clearPaint);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Draw the red delete background
|
|
||||||
background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
|
|
||||||
background.draw(c);
|
|
||||||
|
|
||||||
// Calculate position of delete icon
|
|
||||||
int iconHeight = icon.getIntrinsicHeight();
|
|
||||||
int iconWidth = icon.getIntrinsicWidth();
|
|
||||||
int iconTop = itemView.getTop() + (itemHeight - iconHeight) / 2;
|
|
||||||
int iconMargin = (itemHeight - iconHeight) / 2;
|
|
||||||
int iconLeft = itemView.getRight() - iconMargin - iconWidth;
|
|
||||||
int iconRight = itemView.getRight() - iconMargin;
|
|
||||||
int iconBottom = iconTop + iconHeight;
|
|
||||||
|
|
||||||
// Draw the icon
|
|
||||||
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
|
|
||||||
icon.draw(c);
|
|
||||||
|
|
||||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnSwipeCallback {
|
|
||||||
void onSwipe(int position, int direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnMoveCallback {
|
|
||||||
boolean onMove(int from, int to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.utils;
|
|
||||||
|
|
||||||
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;
|
|
||||||
private T mReferenceValue;
|
|
||||||
|
|
||||||
public ChangeTrackedLiveData(T initialValue, OnValueChangedCallback<T> onValueChanged, OnValueDirtiedCallback onValueDirtied) {
|
|
||||||
super(initialValue);
|
|
||||||
mReferenceValue = initialValue;
|
|
||||||
mOnValueChangedCallback = onValueChanged;
|
|
||||||
if (mOnValueChangedCallback != null) {
|
|
||||||
mOnValueChangedCallback.onValueChanged(initialValue);
|
|
||||||
}
|
|
||||||
mOnValueDirtiedCallback = onValueDirtied;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChangeTrackedLiveData(T initialValue, OnValueChangedCallback<T> callback) {
|
|
||||||
this(initialValue, callback, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChangeTrackedLiveData(T initialValue, OnValueDirtiedCallback callback) {
|
|
||||||
this(initialValue, null, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setReferenceValue(T referenceValue) {
|
|
||||||
mReferenceValue = referenceValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCurrentValueAsReference() {
|
|
||||||
mReferenceValue = getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetValue(T value) {
|
|
||||||
mReferenceValue = value;
|
|
||||||
setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(T value) {
|
|
||||||
if (!Objects.equals(getValue(), value)) {
|
|
||||||
super.setValue(value);
|
|
||||||
|
|
||||||
if (mOnValueChangedCallback != null) {
|
|
||||||
mOnValueChangedCallback.onValueChanged(value);
|
|
||||||
}
|
|
||||||
if (!Objects.equals(mReferenceValue, value) && mOnValueDirtiedCallback != null) {
|
|
||||||
mOnValueDirtiedCallback.onValueDirtied();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueDirtiedCallback {
|
|
||||||
void onValueDirtied();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnValueChangedCallback<T> {
|
|
||||||
void onValueChanged(T value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.utils;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class Logger {
|
|
||||||
public static final String LOG_TAG = "MonsterCards";
|
|
||||||
|
|
||||||
public static void logUnimplementedMethod() {
|
|
||||||
Exception ex = new Exception();
|
|
||||||
StackTraceElement[] stackTrace = ex.getStackTrace();
|
|
||||||
|
|
||||||
String location = stackTrace[1].getClassName() + "." + stackTrace[1].getMethodName() + ":" + stackTrace[1].getLineNumber();
|
|
||||||
logDebug("Method not yet implemented " + location);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logUnhandledError(Throwable e) {
|
|
||||||
StackTraceElement stackTraceElement = e.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
logDebug("Exception was caught but not properly handled " + location);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logUnimplementedFeature(String featureDescription) {
|
|
||||||
Exception ex = new Exception();
|
|
||||||
StackTraceElement[] stackTrace = ex.getStackTrace();
|
|
||||||
|
|
||||||
String location = stackTrace[1].getClassName() + "." + stackTrace[1].getMethodName() + ":" + stackTrace[1].getLineNumber();
|
|
||||||
logDebug("Feature not yet implemented " + featureDescription + " at " + location);
|
|
||||||
}
|
|
||||||
|
|
||||||
//region WTF
|
|
||||||
public static void logWTF(String message) {
|
|
||||||
Log.wtf(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logWTF(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.wtf(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logWTF(String message, Throwable throwable) {
|
|
||||||
Log.wtf(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Error
|
|
||||||
public static void logError(String message) {
|
|
||||||
Log.e(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logError(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.e(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logError(String message, Throwable throwable) {
|
|
||||||
Log.e(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Warning
|
|
||||||
public static void logWarning(String message) {
|
|
||||||
Log.w(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logWarning(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.w(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logWarning(String message, Throwable throwable) {
|
|
||||||
Log.w(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Info
|
|
||||||
public static void logInfo(String message) {
|
|
||||||
Log.i(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logInfo(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.i(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logInfo(String message, Throwable throwable) {
|
|
||||||
Log.i(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Debug
|
|
||||||
public static void logDebug(String message) {
|
|
||||||
Log.d(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logDebug(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.d(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logDebug(String message, Throwable throwable) {
|
|
||||||
Log.d(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
//region Verbose
|
|
||||||
public static void logVerbose(String message) {
|
|
||||||
Log.v(LOG_TAG, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logVerbose(Throwable throwable) {
|
|
||||||
StackTraceElement stackTraceElement = throwable.getStackTrace()[0];
|
|
||||||
|
|
||||||
String location = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":" + stackTraceElement.getLineNumber();
|
|
||||||
String message = String.format("Unexpected error occurred at %s.", location);
|
|
||||||
Log.v(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logVerbose(String message, Throwable throwable) {
|
|
||||||
Log.v(LOG_TAG, message, throwable);
|
|
||||||
}
|
|
||||||
//endregion
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package com.majinnaibu.monstercards.utils;
|
|
||||||
|
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextWatcher;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class TextChangedListener implements TextWatcher {
|
|
||||||
|
|
||||||
private final BeforeTextChangedCallback mBeforeTextChangedCallback;
|
|
||||||
private final OnTextChangedCallback mOnTextChangedCallback;
|
|
||||||
private final AfterTextChangedCallback mAfterTextChangedCallback;
|
|
||||||
|
|
||||||
public TextChangedListener(BeforeTextChangedCallback beforeTextChangedCallback, OnTextChangedCallback onTextChangedCallback, AfterTextChangedCallback afterTextChangedCallback) {
|
|
||||||
mBeforeTextChangedCallback = beforeTextChangedCallback;
|
|
||||||
mOnTextChangedCallback = onTextChangedCallback;
|
|
||||||
mAfterTextChangedCallback = afterTextChangedCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(OnTextChangedCallback callback) {
|
|
||||||
this(null, callback, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(BeforeTextChangedCallback callback) {
|
|
||||||
this(callback, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(AfterTextChangedCallback callback) {
|
|
||||||
this(null, null, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(BeforeTextChangedCallback beforeTextChangedCallback, OnTextChangedCallback onTextChangedCallback) {
|
|
||||||
this(beforeTextChangedCallback, onTextChangedCallback, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(BeforeTextChangedCallback beforeTextChangedCallback, AfterTextChangedCallback afterTextChangedCallback) {
|
|
||||||
this(beforeTextChangedCallback, null, afterTextChangedCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextChangedListener(OnTextChangedCallback onTextChangedCallback, AfterTextChangedCallback afterTextChangedCallback) {
|
|
||||||
this(null, onTextChangedCallback, afterTextChangedCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
if (mBeforeTextChangedCallback != null) {
|
|
||||||
mBeforeTextChangedCallback.beforeTextChanged(s, start, count, after);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
if (mOnTextChangedCallback != null) {
|
|
||||||
mOnTextChangedCallback.onTextChanged(s, start, before, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
if (mAfterTextChangedCallback != null) {
|
|
||||||
mAfterTextChangedCallback.afterTextChanged(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface BeforeTextChangedCallback {
|
|
||||||
void beforeTextChanged(CharSequence s, int start, int count, int after);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface OnTextChangedCallback {
|
|
||||||
void onTextChanged(CharSequence s, int start, int before, int count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface AfterTextChangedCallback {
|
|
||||||
void afterTextChanged(Editable s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:color="@color/colorOnPrimary" android:state_checked="true"/>
|
|
||||||
<item android:color="@color/colorPrimary" android:state_checked="false"/>
|
|
||||||
</selector>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user