Makes monster editor smoother and fixes colors.

This commit is contained in:
2026-09-16 22:04:30 -07:00
parent d63b125175
commit ddb58622d6
14 changed files with 944 additions and 308 deletions

View File

@@ -58,20 +58,11 @@ public class MainActivity extends AppCompatActivity {
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
WindowCompat.setDecorFitsSystemWindows(getWindow(), false); WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
AppCenterInitializer.init(getApplication()); AppCenterInitializer.init(getApplication());
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
View container = findViewById(R.id.container);
if (container != null) {
ViewCompat.setOnApplyWindowInsetsListener(container, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(insets.left, insets.top, insets.right, 0);
return windowInsets;
});
}
BottomNavigationView navView = findViewById(R.id.nav_view); BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each // Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations. // menu should be considered as top level destinations.

View File

@@ -1,9 +1,11 @@
package com.majinnaibu.monstercards.ui.editmonster; package com.majinnaibu.monstercards.ui.editmonster;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
@@ -14,7 +16,7 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavBackStackEntry;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.NavDirections; import androidx.navigation.NavDirections;
import androidx.navigation.Navigation; import androidx.navigation.fragment.NavHostFragment;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.R;
@@ -22,10 +24,11 @@ import com.majinnaibu.monstercards.data.MonsterRepository;
import com.majinnaibu.monstercards.data.enums.StringType; import com.majinnaibu.monstercards.data.enums.StringType;
import com.majinnaibu.monstercards.data.enums.TraitType; import com.majinnaibu.monstercards.data.enums.TraitType;
import com.majinnaibu.monstercards.models.Monster; import com.majinnaibu.monstercards.models.Monster;
import com.majinnaibu.monstercards.ui.monster.MonsterDetailFragmentArgs;
import com.majinnaibu.monstercards.ui.shared.MCFragment; import com.majinnaibu.monstercards.ui.shared.MCFragment;
import com.majinnaibu.monstercards.utils.Logger; import com.majinnaibu.monstercards.utils.Logger;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@@ -43,21 +46,34 @@ public class EditMonsterFragment extends MCFragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @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); View root = inflater.inflate(R.layout.fragment_edit_monster, container, false);
mHolder = new ViewHolder(root); mHolder = new ViewHolder(root);
MonsterRepository repository = getMonsterRepository();
Bundle arguments = getArguments();
if (arguments == null) {
Logger.logError("Arguments bundle is null in EditMonsterFragment");
return root;
}
String monsterIdStr = EditMonsterFragmentArgs.fromBundle(arguments).getMonsterId();
if (monsterIdStr == null || monsterIdStr.isEmpty()) {
Logger.logError("monsterId is null or empty in EditMonsterFragment");
return root;
}
UUID monsterId = UUID.fromString(monsterIdStr);
try {
NavController navController = NavHostFragment.findNavController(this);
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
} catch (Exception e) {
mViewModel = new ViewModelProvider(this).get(EditMonsterViewModel.class);
}
setTitle(getString(R.string.title_editMonster_fmt, getString(R.string.default_monster_name))); 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)) { if (mViewModel.hasError() || !mViewModel.hasLoaded() || !Objects.equals(mViewModel.getMonsterId().getValue(), monsterId)) {
repository.getMonster(monsterId).toObservable() repository.getMonster(monsterId).toObservable()
.firstOrError() .firstOrError()
@@ -73,7 +89,6 @@ public class EditMonsterFragment extends MCFragment {
@Override @Override
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
// TODO: Show an error state.
Logger.logError(e); Logger.logError(e);
mViewModel.setHasError(true); mViewModel.setHasError(true);
mViewModel.setErrorMessage(e.toString()); mViewModel.setErrorMessage(e.toString());
@@ -82,101 +97,9 @@ public class EditMonsterFragment extends MCFragment {
}); });
} }
mHolder.basicInfoButton.setOnClickListener(v -> { setupAccordions();
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditBasicInfoFragment(); setupSummaries();
Navigation.findNavController(requireView()).navigate(action); setupSubClickListeners();
});
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) { requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
@Override @Override
@@ -187,7 +110,6 @@ public class EditMonsterFragment extends MCFragment {
alertDialog.setTitle("Unsaved Changes"); alertDialog.setTitle("Unsaved Changes");
alertDialog.setMessage("Do you want to save your changes?"); alertDialog.setMessage("Do you want to save your changes?");
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Save", (dialog, id) -> { 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()) getMonsterRepository().saveMonster(mViewModel.buildMonster())
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@@ -195,29 +117,23 @@ public class EditMonsterFragment extends MCFragment {
new DisposableCompletableObserver() { new DisposableCompletableObserver() {
@Override @Override
public void onComplete() { public void onComplete() {
Navigation.findNavController(requireView()).navigateUp(); NavHostFragment.findNavController(EditMonsterFragment.this).navigateUp();
} }
@Override @Override
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
Logger.logError("Error creating monster", e); Logger.logError("Error saving monster", e);
assert view != null; assert view != null;
Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG) Snackbar.make(view, getString(R.string.snackbar_failed_to_create_monster), Snackbar.LENGTH_LONG)
.setAction("Action", null).show(); .setAction("Action", null).show();
} }
}); });
}); });
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Discard", (dialog, id) -> { alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Discard", (dialog, id) -> NavHostFragment.findNavController(EditMonsterFragment.this).navigateUp());
// Navigate up ignoring unsaved changes. alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Cancel", (dialog, id) -> {});
Navigation.findNavController(requireView()).navigateUp();
});
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Cancel", (dialog, id) -> {
// Do nothing.
});
alertDialog.show(); alertDialog.show();
} else { } else {
// No changes so we can safely leave. NavHostFragment.findNavController(EditMonsterFragment.this).navigateUp();
Navigation.findNavController(requireView()).navigateUp();
} }
} }
}); });
@@ -225,42 +141,344 @@ public class EditMonsterFragment extends MCFragment {
return root; return root;
} }
private static class ViewHolder { private void setupAccordions() {
if (mHolder.headerBasicInfo != null && mHolder.bodyBasicInfo != null && mHolder.chevronBasicInfo != null) {
setupAccordion(mHolder.headerBasicInfo, mHolder.bodyBasicInfo, mHolder.chevronBasicInfo);
}
if (mHolder.headerCombatAbilities != null && mHolder.bodyCombatAbilities != null && mHolder.chevronCombatAbilities != null) {
setupAccordion(mHolder.headerCombatAbilities, mHolder.bodyCombatAbilities, mHolder.chevronCombatAbilities);
}
if (mHolder.headerSavesSkillsLanguages != null && mHolder.bodySavesSkillsLanguages != null && mHolder.chevronSavesSkillsLanguages != null) {
setupAccordion(mHolder.headerSavesSkillsLanguages, mHolder.bodySavesSkillsLanguages, mHolder.chevronSavesSkillsLanguages);
}
if (mHolder.headerDefenses != null && mHolder.bodyDefenses != null && mHolder.chevronDefenses != null) {
setupAccordion(mHolder.headerDefenses, mHolder.bodyDefenses, mHolder.chevronDefenses);
}
if (mHolder.headerTraitsActions != null && mHolder.bodyTraitsActions != null && mHolder.chevronTraitsActions != null) {
setupAccordion(mHolder.headerTraitsActions, mHolder.bodyTraitsActions, mHolder.chevronTraitsActions);
}
}
TextView basicInfoButton; private void setupAccordion(View header, View body, ImageView chevron) {
TextView armorButton; header.setOnClickListener(v -> {
TextView speedButton; boolean isExpanded = body.getVisibility() == View.VISIBLE;
TextView abilityScoresButton; body.setVisibility(isExpanded ? View.GONE : View.VISIBLE);
TextView savingThrows; chevron.setImageResource(isExpanded ? R.drawable.ic_expand_more_24 : R.drawable.ic_expand_less_24);
TextView skills; });
TextView conditionImmunities; }
TextView damageImmunities;
TextView damageResistances; private void setupSummaries() {
TextView damageVulnerabilities; mViewModel.getName().observe(getViewLifecycleOwner(), v -> updateBasicInfoSummary());
TextView senses; mViewModel.getSize().observe(getViewLifecycleOwner(), v -> updateBasicInfoSummary());
TextView languages; mViewModel.getType().observe(getViewLifecycleOwner(), v -> updateBasicInfoSummary());
TextView challengeRating; mViewModel.getChallengeRating().observe(getViewLifecycleOwner(), v -> updateBasicInfoSummary());
TextView abilities;
TextView actions; mViewModel.getStrength().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
TextView reactions; mViewModel.getDexterity().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
TextView legendaryActions; mViewModel.getConstitution().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
TextView lairActions; mViewModel.getIntelligence().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
TextView regionalActions; mViewModel.getWisdom().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
mViewModel.getCharisma().observe(getViewLifecycleOwner(), v -> updateCombatAbilitiesSummary());
mViewModel.getSkills().observe(getViewLifecycleOwner(), v -> updateSavesSkillsSummary());
mViewModel.getLanguages().observe(getViewLifecycleOwner(), v -> updateSavesSkillsSummary());
mViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), v -> updateDefensesSummary());
mViewModel.getDamageImmunities().observe(getViewLifecycleOwner(), v -> updateDefensesSummary());
mViewModel.getDamageResistances().observe(getViewLifecycleOwner(), v -> updateDefensesSummary());
mViewModel.getDamageVulnerabilities().observe(getViewLifecycleOwner(), v -> updateDefensesSummary());
mViewModel.getAbilities().observe(getViewLifecycleOwner(), v -> updateTraitsActionsSummary());
mViewModel.getActions().observe(getViewLifecycleOwner(), v -> updateTraitsActionsSummary());
mViewModel.getReactions().observe(getViewLifecycleOwner(), v -> updateTraitsActionsSummary());
}
private void updateBasicInfoSummary() {
if (mHolder.summaryBasicInfo == null) return;
String name = mViewModel.getName().getValue();
String size = mViewModel.getSize().getValue();
String type = mViewModel.getType().getValue();
List<String> parts = new ArrayList<>();
if (!TextUtils.isEmpty(name)) parts.add(name);
if (!TextUtils.isEmpty(size)) parts.add(size);
if (!TextUtils.isEmpty(type)) parts.add(type);
mHolder.summaryBasicInfo.setText(parts.isEmpty() ? "Tap to edit basic info" : TextUtils.join(", ", parts));
}
private void updateCombatAbilitiesSummary() {
if (mHolder.summaryCombatAbilities == null) return;
Integer str = mViewModel.getStrength().getValue();
Integer dex = mViewModel.getDexterity().getValue();
Integer con = mViewModel.getConstitution().getValue();
Integer intel = mViewModel.getIntelligence().getValue();
Integer wis = mViewModel.getWisdom().getValue();
Integer cha = mViewModel.getCharisma().getValue();
String summary = String.format("STR %d | DEX %d | CON %d | INT %d | WIS %d | CHA %d",
str != null ? str : 10,
dex != null ? dex : 10,
con != null ? con : 10,
intel != null ? intel : 10,
wis != null ? wis : 10,
cha != null ? cha : 10);
mHolder.summaryCombatAbilities.setText(summary);
}
private void updateSavesSkillsSummary() {
if (mHolder.summarySavesSkillsLanguages == null) return;
int skillsCount = mViewModel.getSkills().getValue() != null ? mViewModel.getSkills().getValue().size() : 0;
int languagesCount = mViewModel.getLanguages().getValue() != null ? mViewModel.getLanguages().getValue().size() : 0;
mHolder.summarySavesSkillsLanguages.setText(String.format("%d Skills, %d Languages", skillsCount, languagesCount));
}
private void updateDefensesSummary() {
if (mHolder.summaryDefenses == null) return;
List<String> defenses = new ArrayList<>();
if (mViewModel.getConditionImmunities().getValue() != null && !mViewModel.getConditionImmunities().getValue().isEmpty()) {
defenses.add(mViewModel.getConditionImmunities().getValue().size() + " Condition Immunities");
}
if (mViewModel.getDamageImmunities().getValue() != null && !mViewModel.getDamageImmunities().getValue().isEmpty()) {
defenses.add(mViewModel.getDamageImmunities().getValue().size() + " Damage Immunities");
}
if (mViewModel.getDamageResistances().getValue() != null && !mViewModel.getDamageResistances().getValue().isEmpty()) {
defenses.add(mViewModel.getDamageResistances().getValue().size() + " Resistances");
}
mHolder.summaryDefenses.setText(defenses.isEmpty() ? "None" : TextUtils.join(", ", defenses));
}
private void updateTraitsActionsSummary() {
if (mHolder.summaryTraitsActions == null) return;
int abilitiesCount = mViewModel.getAbilities().getValue() != null ? mViewModel.getAbilities().getValue().size() : 0;
int actionsCount = mViewModel.getActions().getValue() != null ? mViewModel.getActions().getValue().size() : 0;
int reactionsCount = mViewModel.getReactions().getValue() != null ? mViewModel.getReactions().getValue().size() : 0;
mHolder.summaryTraitsActions.setText(String.format("%d Abilities, %d Actions, %d Reactions", abilitiesCount, actionsCount, reactionsCount));
}
private void setupSubClickListeners() {
if (mHolder.basicInfoButton != null) {
mHolder.basicInfoButton.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditBasicInfoFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.challengeRating != null) {
mHolder.challengeRating.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditChallengeRatingFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.armorButton != null) {
mHolder.armorButton.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditArmorFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.speedButton != null) {
mHolder.speedButton.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSpeedFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.abilityScoresButton != null) {
mHolder.abilityScoresButton.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditAbilityScoresFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.savingThrows != null) {
mHolder.savingThrows.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSavingThrowsFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.skills != null) {
mHolder.skills.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditSkillsFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.senses != null) {
mHolder.senses.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.SENSE);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.languages != null) {
mHolder.languages.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditLanguagesFragment();
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.conditionImmunities != null) {
mHolder.conditionImmunities.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.CONDITION_IMMUNITY);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.damageImmunities != null) {
mHolder.damageImmunities.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_IMMUNITY);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.damageResistances != null) {
mHolder.damageResistances.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_RESISTANCE);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.damageVulnerabilities != null) {
mHolder.damageVulnerabilities.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditStringsFragment(StringType.DAMAGE_VULNERABILITY);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.abilities != null) {
mHolder.abilities.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.ABILITY);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.actions != null) {
mHolder.actions.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.ACTION);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.reactions != null) {
mHolder.reactions.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.REACTIONS);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.legendaryActions != null) {
mHolder.legendaryActions.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.LEGENDARY_ACTION);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.lairActions != null) {
mHolder.lairActions.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.LAIR_ACTION);
NavHostFragment.findNavController(this).navigate(action);
});
}
if (mHolder.regionalActions != null) {
mHolder.regionalActions.setOnClickListener(v -> {
NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditTraitListFragment(TraitType.REGIONAL_ACTION);
NavHostFragment.findNavController(this).navigate(action);
});
}
}
private static class ViewHolder {
final View headerBasicInfo;
final View bodyBasicInfo;
final ImageView chevronBasicInfo;
final TextView summaryBasicInfo;
final View headerCombatAbilities;
final View bodyCombatAbilities;
final ImageView chevronCombatAbilities;
final TextView summaryCombatAbilities;
final View headerSavesSkillsLanguages;
final View bodySavesSkillsLanguages;
final ImageView chevronSavesSkillsLanguages;
final TextView summarySavesSkillsLanguages;
final View headerDefenses;
final View bodyDefenses;
final ImageView chevronDefenses;
final TextView summaryDefenses;
final View headerTraitsActions;
final View bodyTraitsActions;
final ImageView chevronTraitsActions;
final TextView summaryTraitsActions;
final TextView basicInfoButton;
final TextView challengeRating;
final TextView armorButton;
final TextView speedButton;
final TextView abilityScoresButton;
final TextView savingThrows;
final TextView skills;
final TextView senses;
final TextView languages;
final TextView conditionImmunities;
final TextView damageImmunities;
final TextView damageResistances;
final TextView damageVulnerabilities;
final TextView abilities;
final TextView actions;
final TextView reactions;
final TextView legendaryActions;
final TextView lairActions;
final TextView regionalActions;
ViewHolder(@NonNull View root) { ViewHolder(@NonNull View root) {
headerBasicInfo = root.findViewById(R.id.headerBasicInfo);
bodyBasicInfo = root.findViewById(R.id.bodyBasicInfo);
chevronBasicInfo = root.findViewById(R.id.chevronBasicInfo);
summaryBasicInfo = root.findViewById(R.id.summaryBasicInfo);
headerCombatAbilities = root.findViewById(R.id.headerCombatAbilities);
bodyCombatAbilities = root.findViewById(R.id.bodyCombatAbilities);
chevronCombatAbilities = root.findViewById(R.id.chevronCombatAbilities);
summaryCombatAbilities = root.findViewById(R.id.summaryCombatAbilities);
headerSavesSkillsLanguages = root.findViewById(R.id.headerSavesSkillsLanguages);
bodySavesSkillsLanguages = root.findViewById(R.id.bodySavesSkillsLanguages);
chevronSavesSkillsLanguages = root.findViewById(R.id.chevronSavesSkillsLanguages);
summarySavesSkillsLanguages = root.findViewById(R.id.summarySavesSkillsLanguages);
headerDefenses = root.findViewById(R.id.headerDefenses);
bodyDefenses = root.findViewById(R.id.bodyDefenses);
chevronDefenses = root.findViewById(R.id.chevronDefenses);
summaryDefenses = root.findViewById(R.id.summaryDefenses);
headerTraitsActions = root.findViewById(R.id.headerTraitsActions);
bodyTraitsActions = root.findViewById(R.id.bodyTraitsActions);
chevronTraitsActions = root.findViewById(R.id.chevronTraitsActions);
summaryTraitsActions = root.findViewById(R.id.summaryTraitsActions);
basicInfoButton = root.findViewById(R.id.basicInfo); basicInfoButton = root.findViewById(R.id.basicInfo);
challengeRating = root.findViewById(R.id.challengeRating);
armorButton = root.findViewById(R.id.armor); armorButton = root.findViewById(R.id.armor);
speedButton = root.findViewById(R.id.speed); speedButton = root.findViewById(R.id.speed);
abilityScoresButton = root.findViewById(R.id.abilityScores); abilityScoresButton = root.findViewById(R.id.abilityScores);
savingThrows = root.findViewById(R.id.savingThrows); savingThrows = root.findViewById(R.id.savingThrows);
skills = root.findViewById(R.id.skills); skills = root.findViewById(R.id.skills);
senses = root.findViewById(R.id.senses);
languages = root.findViewById(R.id.languages);
conditionImmunities = root.findViewById(R.id.conditionImmunities); conditionImmunities = root.findViewById(R.id.conditionImmunities);
damageImmunities = root.findViewById(R.id.damageImmunities); damageImmunities = root.findViewById(R.id.damageImmunities);
damageResistances = root.findViewById(R.id.damageResistances); damageResistances = root.findViewById(R.id.damageResistances);
damageVulnerabilities = root.findViewById(R.id.damageVulnerabilities); 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); abilities = root.findViewById(R.id.abilities);
actions = root.findViewById(R.id.actions); actions = root.findViewById(R.id.actions);
reactions = root.findViewById(R.id.reactions); reactions = root.findViewById(R.id.reactions);

View File

@@ -702,6 +702,38 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
return mDamageResistances; return mDamageResistances;
} }
public LiveData<List<String>> getDamageVulnerabilities() {
return mDamageVulnerabilities;
}
public LiveData<List<String>> getConditionImmunities() {
return mConditionImmunities;
}
public LiveData<List<Trait>> getAbilities() {
return mAbilities;
}
public LiveData<List<Trait>> getActions() {
return mActions;
}
public LiveData<List<Trait>> getReactions() {
return mReactions;
}
public LiveData<List<Trait>> getLairActions() {
return mLairActions;
}
public LiveData<List<Trait>> getLegendaryActions() {
return mLegendaryActions;
}
public LiveData<List<Trait>> getRegionalActions() {
return mRegionalActions;
}
public LiveData<List<Language>> getLanguages() { public LiveData<List<Language>> getLanguages() {
return mLanguages; return mLanguages;
} }

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
</vector>

View File

@@ -59,6 +59,7 @@
android:id="@+id/decrement" android:id="@+id/decrement"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:paddingVertical="8dp" android:paddingVertical="8dp"
android:text="@string/label_decrement_field" android:text="@string/label_decrement_field"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View File

@@ -4,7 +4,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.editmonster.EditBasicInfoFragment"> android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditAbilityScoresFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -4,7 +4,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.editmonster.EditBasicInfoFragment"> android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditArmorFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -4,6 +4,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditBasicInfoFragment"> tools:context=".ui.editmonster.EditBasicInfoFragment">
<LinearLayout <LinearLayout

View File

@@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditChallengeRatingFragment"> tools:context=".ui.editmonster.EditChallengeRatingFragment">
<LinearLayout <LinearLayout

View File

@@ -3,187 +3,545 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="8dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="@dimen/text_margin"
android:orientation="vertical" android:orientation="vertical"
android:showDividers="middle"
tools:context=".ui.editmonster.EditMonsterFragment"> tools:context=".ui.editmonster.EditMonsterFragment">
<TextView <!-- Card 1: Basic Info & Challenge Rating -->
android:id="@+id/basicInfo" <com.google.android.material.card.MaterialCardView
android:id="@+id/cardBasicInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_marginBottom="8dp"
android:text="@string/label_basic_info" app:cardCornerRadius="8dp"
android:textSize="@dimen/text_h4_size" app:cardElevation="2dp">
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <LinearLayout
android:id="@+id/armor" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:orientation="vertical">
android:layout_margin="@dimen/text_margin"
android:text="@string/label_armor"
android:textSize="@dimen/text_h4_size"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <RelativeLayout
android:id="@+id/speed" android:id="@+id/headerBasicInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_speed" android:clickable="true"
android:textSize="@dimen/text_h4_size" android:focusable="true"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:padding="16dp">
<TextView <TextView
android:id="@+id/abilityScores" android:id="@+id/titleBasicInfo"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_alignParentStart="true"
android:text="@string/label_ability_scores" android:text="Basic Info &amp; Challenge Rating"
android:textSize="@dimen/text_h4_size" android:textColor="?android:attr/textColorPrimary"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="18sp"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/savingThrows" android:id="@+id/summaryBasicInfo"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_below="@id/titleBasicInfo"
android:text="@string/label_saving_throws" android:layout_alignParentStart="true"
android:textSize="@dimen/text_h4_size" android:layout_marginTop="4dp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:layout_toStartOf="@+id/chevronBasicInfo"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
tools:text="Goblin — Small humanoid, CR 1/4" />
<TextView <ImageView
android:id="@+id/skills" android:id="@+id/chevronBasicInfo"
android:layout_width="match_parent" android:layout_width="24dp"
android:layout_height="wrap_content" android:layout_height="24dp"
android:layout_margin="@dimen/text_margin" android:layout_alignParentEnd="true"
android:text="@string/label_skills" android:layout_centerVertical="true"
android:textSize="@dimen/text_h4_size" android:contentDescription="Expand/Collapse"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:src="@drawable/ic_expand_more_24" />
</RelativeLayout>
<TextView <LinearLayout
android:id="@+id/conditionImmunities" android:id="@+id/bodyBasicInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:divider="?android:attr/dividerVertical"
android:text="@string/label_condition_immunities" android:dividerPadding="8dp"
android:textSize="@dimen/text_h4_size" android:orientation="vertical"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:showDividers="middle"
android:visibility="gone">
<TextView <TextView
android:id="@+id/damageImmunities" android:id="@+id/basicInfo"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_damage_immunities" android:padding="16dp"
android:textSize="@dimen/text_h4_size" android:text="@string/label_basic_info"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <TextView
android:id="@+id/damageResistances" android:id="@+id/challengeRating"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_damage_resistances" android:padding="16dp"
android:textSize="@dimen/text_h4_size" android:text="@string/label_challenge_rating"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<TextView <!-- Card 2: Armor, Speed & Ability Scores -->
android:id="@+id/damageVulnerabilities" <com.google.android.material.card.MaterialCardView
android:id="@+id/cardCombatAbilities"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_marginBottom="8dp"
android:text="@string/label_damage_vulnerabilities" app:cardCornerRadius="8dp"
android:textSize="@dimen/text_h4_size" app:cardElevation="2dp">
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <LinearLayout
android:id="@+id/senses" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:orientation="vertical">
android:layout_margin="@dimen/text_margin"
android:text="@string/label_senses"
android:textSize="@dimen/text_h4_size"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <RelativeLayout
android:id="@+id/languages" android:id="@+id/headerCombatAbilities"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_languages" android:clickable="true"
android:textSize="@dimen/text_h4_size" android:focusable="true"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:padding="16dp">
<TextView <TextView
android:id="@+id/challengeRating" android:id="@+id/titleCombatAbilities"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_alignParentStart="true"
android:text="@string/label_challenge_rating" android:text="Armor, Speed &amp; Ability Scores"
android:textSize="@dimen/text_h4_size" android:textColor="?android:attr/textColorPrimary"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="18sp"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/abilities" android:id="@+id/summaryCombatAbilities"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_below="@id/titleCombatAbilities"
android:text="@string/label_abilities" android:layout_alignParentStart="true"
android:textSize="@dimen/text_h4_size" android:layout_marginTop="4dp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:layout_toStartOf="@+id/chevronCombatAbilities"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
tools:text="STR 8 | DEX 14 | CON 10 | INT 10 | WIS 14 | CHA 15" />
<TextView <ImageView
android:id="@+id/actions" android:id="@+id/chevronCombatAbilities"
android:layout_width="match_parent" android:layout_width="24dp"
android:layout_height="wrap_content" android:layout_height="24dp"
android:layout_margin="@dimen/text_margin" android:layout_alignParentEnd="true"
android:text="@string/label_actions" android:layout_centerVertical="true"
android:textSize="@dimen/text_h4_size" android:contentDescription="Expand/Collapse"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:src="@drawable/ic_expand_more_24" />
</RelativeLayout>
<TextView <LinearLayout
android:id="@+id/reactions" android:id="@+id/bodyCombatAbilities"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:divider="?android:attr/dividerVertical"
android:text="@string/label_reactions" android:dividerPadding="8dp"
android:textSize="@dimen/text_h4_size" android:orientation="vertical"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:showDividers="middle"
android:visibility="gone">
<TextView <TextView
android:id="@+id/legendaryActions" android:id="@+id/armor"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_legendary_actions" android:padding="16dp"
android:textSize="@dimen/text_h4_size" android:text="@string/label_armor"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <TextView
android:id="@+id/lairActions" android:id="@+id/speed"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:background="?attr/selectableItemBackground"
android:text="@string/label_lair_actions" android:padding="16dp"
android:textSize="@dimen/text_h4_size" android:text="@string/label_speed"
app:drawableEndCompat="@drawable/ic_chevron_right_24" /> android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView <TextView
android:id="@+id/regionalActions" android:id="@+id/abilityScores"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_ability_scores"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Card 3: Saves, Skills & Languages -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardSavesSkillsLanguages"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_marginBottom="8dp"
android:text="@string/label_regional_effects" app:cardCornerRadius="8dp"
android:textSize="@dimen/text_h4_size" app:cardElevation="2dp">
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/headerSavesSkillsLanguages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp">
<TextView
android:id="@+id/titleSavesSkillsLanguages"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="Saves, Skills &amp; Languages"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/summarySavesSkillsLanguages"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/titleSavesSkillsLanguages"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_toStartOf="@+id/chevronSavesSkillsLanguages"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
tools:text="3 Saves, 2 Skills, Common &amp; Goblin" />
<ImageView
android:id="@+id/chevronSavesSkillsLanguages"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="Expand/Collapse"
android:src="@drawable/ic_expand_more_24" />
</RelativeLayout>
<LinearLayout
android:id="@+id/bodySavesSkillsLanguages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="8dp"
android:orientation="vertical"
android:showDividers="middle"
android:visibility="gone">
<TextView
android:id="@+id/savingThrows"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_saving_throws"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/skills"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_skills"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/senses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_senses"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_languages"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Card 4: Defenses & Immunities -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardDefenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/headerDefenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp">
<TextView
android:id="@+id/titleDefenses"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="Defenses &amp; Immunities"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/summaryDefenses"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/titleDefenses"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_toStartOf="@+id/chevronDefenses"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
tools:text="Poison Immunity, Fire Resistance" />
<ImageView
android:id="@+id/chevronDefenses"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="Expand/Collapse"
android:src="@drawable/ic_expand_more_24" />
</RelativeLayout>
<LinearLayout
android:id="@+id/bodyDefenses"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="8dp"
android:orientation="vertical"
android:showDividers="middle"
android:visibility="gone">
<TextView
android:id="@+id/conditionImmunities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_condition_immunities"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/damageImmunities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_damage_immunities"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/damageResistances"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_damage_resistances"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/damageVulnerabilities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_damage_vulnerabilities"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Card 5: Abilities, Actions & Traits -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardTraitsActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/headerTraitsActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp">
<TextView
android:id="@+id/titleTraitsActions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="Abilities, Actions &amp; Traits"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/summaryTraitsActions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/titleTraitsActions"
android:layout_alignParentStart="true"
android:layout_marginTop="4dp"
android:layout_toStartOf="@+id/chevronTraitsActions"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
tools:text="2 Abilities, 2 Actions, 1 Reaction" />
<ImageView
android:id="@+id/chevronTraitsActions"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="Expand/Collapse"
android:src="@drawable/ic_expand_more_24" />
</RelativeLayout>
<LinearLayout
android:id="@+id/bodyTraitsActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="8dp"
android:orientation="vertical"
android:showDividers="middle"
android:visibility="gone">
<TextView
android:id="@+id/abilities"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_abilities"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_actions"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/reactions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_reactions"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/legendaryActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_legendary_actions"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/lairActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_lair_actions"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
<TextView
android:id="@+id/regionalActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:padding="16dp"
android:text="@string/label_regional_effects"
android:textSize="16sp"
app:drawableEndCompat="@drawable/ic_chevron_right_24" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@@ -3,7 +3,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditSavingThrowsFragment"> tools:context=".ui.editmonster.EditSavingThrowsFragment">
<LinearLayout <LinearLayout

View File

@@ -4,7 +4,9 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.editmonster.EditBasicInfoFragment"> android:clipToPadding="false"
android:padding="16dp"
tools:context=".ui.editmonster.EditSpeedFragment">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -1,10 +1,15 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorSecondary">@color/colorSecondary</item>
<item name="colorSecondaryVariant">@color/colorSecondaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
<item name="colorOnPrimary">#ffffff</item>
<item name="colorOnSecondary">#000000</item>
</style> </style>
</resources> </resources>