diff --git a/Android/.idea/inspectionProfiles/Project_Default.xml b/Android/.idea/inspectionProfiles/Project_Default.xml index 082b356..5d018a6 100644 --- a/Android/.idea/inspectionProfiles/Project_Default.xml +++ b/Android/.idea/inspectionProfiles/Project_Default.xml @@ -1,6 +1,7 @@ \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/collections/CollectionsFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/collections/CollectionsFragment.java index 45b711d..1245bcb 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/collections/CollectionsFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/collections/CollectionsFragment.java @@ -8,20 +8,19 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; import com.majinnaibu.monstercards.R; +import com.majinnaibu.monstercards.ui.shared.MCFragment; -public class CollectionsFragment extends Fragment { +public class CollectionsFragment extends MCFragment { private CollectionsViewModel collectionsViewModel; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - collectionsViewModel = - ViewModelProviders.of(this).get(CollectionsViewModel.class); + 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(), new Observer() { diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java index 22ac979..1b1eb5f 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardFragment.java @@ -7,29 +7,21 @@ import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; import com.majinnaibu.monstercards.R; +import com.majinnaibu.monstercards.ui.shared.MCFragment; -public class DashboardFragment extends Fragment { +public class DashboardFragment extends MCFragment { private DashboardViewModel dashboardViewModel; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - dashboardViewModel = - ViewModelProviders.of(this).get(DashboardViewModel.class); + dashboardViewModel = new ViewModelProvider(this).get(DashboardViewModel.class); View root = inflater.inflate(R.layout.fragment_dashboard, container, false); final TextView textView = root.findViewById(R.id.text_dashboard); - dashboardViewModel.getText().observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(@Nullable String s) { - textView.setText(s); - } - }); + dashboardViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); return root; } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardViewModel.java index 4748dd1..97d3340 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/dashboard/DashboardViewModel.java @@ -5,8 +5,7 @@ import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; public class DashboardViewModel extends ViewModel { - - private MutableLiveData mText; + private final MutableLiveData mText; public DashboardViewModel() { mText = new MutableLiveData<>(); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java index 697a287..c1eea6e 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditAbilityScoresFragment.java @@ -13,6 +13,7 @@ import androidx.navigation.Navigation; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.ui.components.Stepper; +import com.majinnaibu.monstercards.ui.shared.MCFragment; public class EditAbilityScoresFragment extends Fragment { private final String ABILITY_SCORE_FORMAT = "%d (%+d)"; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditArmorFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditArmorFragment.java index a913d27..75b159a 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditArmorFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditArmorFragment.java @@ -13,7 +13,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SwitchCompat; -import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavController; @@ -22,10 +21,10 @@ 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.shared.MCFragment; import com.majinnaibu.monstercards.utils.TextChangedListener; -@SuppressWarnings("FieldCanBeLocal") -public class EditArmorFragment extends Fragment { +public class EditArmorFragment extends MCFragment { private EditMonsterViewModel mViewModel; private ViewHolder mHolder; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditBasicInfoFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditBasicInfoFragment.java index 9a99c88..1ccf3e1 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditBasicInfoFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditBasicInfoFragment.java @@ -13,10 +13,9 @@ import androidx.navigation.Navigation; import com.google.android.material.switchmaterial.SwitchMaterial; import com.majinnaibu.monstercards.R; -import com.majinnaibu.monstercards.ui.MCFragment; +import com.majinnaibu.monstercards.ui.shared.MCFragment; import com.majinnaibu.monstercards.utils.TextChangedListener; -@SuppressWarnings("FieldCanBeLocal") public class EditBasicInfoFragment extends MCFragment { private EditMonsterViewModel mViewModel; private ViewHolder mHolder; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditChallengeRatingFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditChallengeRatingFragment.java index ec4b724..c2b0008 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditChallengeRatingFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditChallengeRatingFragment.java @@ -12,7 +12,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavController; @@ -21,9 +20,10 @@ 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 Fragment { +public class EditChallengeRatingFragment extends MCFragment { private EditMonsterViewModel mViewModel; private ViewHolder mHolder; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java new file mode 100644 index 0000000..ac3e605 --- /dev/null +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java @@ -0,0 +1,95 @@ +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.fragment.app.Fragment; +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.ui.shared.SwipeToDeleteCallback; +import com.majinnaibu.monstercards.utils.Logger; + +import org.jetbrains.annotations.NotNull; + +/** + * A fragment representing a list of Items. + */ +public class EditConditionImmunitiesFragment extends Fragment { + private EditMonsterViewModel mViewModel; + private ViewHolder mHolder; + + private void navigateToEditConditionImmunity(String condition) { + NavDirections action = EditConditionImmunitiesFragmentDirections.actionEditConditionImmunitiesFragmentToEditConditionImmunity(condition); + View view = getView(); + assert view != null; + Navigation.findNavController(view).navigate(action); + } + + @Nullable + @Override + public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { + NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment); + NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation); + mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class); + View root = inflater.inflate(R.layout.fragment_edit_condition_immunities_list, container, false); + mHolder = new ViewHolder(root); + setupRecyclerView(mHolder.list); + setupAddConditionImmunityButton(mHolder.addConditionImmunity); + return root; + } + + private void setupRecyclerView(@NonNull RecyclerView recyclerView) { + Context context = requireContext(); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + recyclerView.setLayoutManager(layoutManager); + + mViewModel.getConditionImmunities().observe(getViewLifecycleOwner(), conditionImmunities -> { + EditConditionImmunitiesRecyclerViewAdapter adapter = new EditConditionImmunitiesRecyclerViewAdapter(mViewModel.getConditionImmunitiesArray(), condition -> { + if (condition != null) { + navigateToEditConditionImmunity(condition); + } else { + Logger.logError("Can't navigate to EditConditionImmunityFragment with a null condition"); + } + }); + recyclerView.setAdapter(adapter); + }); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation()); + recyclerView.addItemDecoration(dividerItemDecoration); + + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, mViewModel::removeConditionImmunity)); + itemTouchHelper.attachToRecyclerView(recyclerView); + } + + private void setupAddConditionImmunityButton(@NonNull FloatingActionButton fab) { + fab.setOnClickListener(view -> { + String condition = mViewModel.addNewConditionImmunity(); + navigateToEditConditionImmunity(condition); + }); + } + + private static class ViewHolder { + RecyclerView list; + FloatingActionButton addConditionImmunity; + + ViewHolder(View root) { + list = root.findViewById(R.id.list); + addConditionImmunity = root.findViewById(R.id.add_condition_immunity); + } + } +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java index e461b0b..4af2a85 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java @@ -20,8 +20,8 @@ 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.MCFragment; import com.majinnaibu.monstercards.ui.monster.MonsterDetailFragmentArgs; +import com.majinnaibu.monstercards.ui.shared.MCFragment; import com.majinnaibu.monstercards.utils.Logger; import java.util.Objects; @@ -32,7 +32,6 @@ import io.reactivex.rxjava3.observers.DisposableCompletableObserver; import io.reactivex.rxjava3.observers.DisposableSingleObserver; import io.reactivex.rxjava3.schedulers.Schedulers; -@SuppressWarnings("FieldCanBeLocal") public class EditMonsterFragment extends MCFragment { private EditMonsterViewModel mViewModel; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java index 6fa13a8..1af08b7 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterViewModel.java @@ -3,7 +3,6 @@ package com.majinnaibu.monstercards.ui.editmonster; import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; import com.majinnaibu.monstercards.data.enums.AbilityScore; import com.majinnaibu.monstercards.data.enums.AdvantageType; @@ -15,22 +14,22 @@ 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 com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel; import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.UUID; @SuppressWarnings({"ConstantConditions", "unused"}) -public class EditMonsterViewModel extends ViewModel { +public class EditMonsterViewModel extends ChangeTrackedViewModel { private final ChangeTrackedLiveData mMonsterId; private final MutableLiveData mHasError; private final MutableLiveData mHasLoaded; - private final MutableLiveData mHasChanges; private final ChangeTrackedLiveData mHasCustomHitPoints; private final ChangeTrackedLiveData mHasShield; private final ChangeTrackedLiveData mCanHover; @@ -78,83 +77,82 @@ public class EditMonsterViewModel extends ViewModel { private final ChangeTrackedLiveData mUnderstandsButDescription; private final ChangeTrackedLiveData> mSkills; private final ChangeTrackedLiveData> mSenses; - private final ChangeTrackedLiveData> mDamageImmunities; - private final ChangeTrackedLiveData> mDamageResistances; - private final ChangeTrackedLiveData> mDamageVulnerabilities; - private final ChangeTrackedLiveData> mConditionImmunities; - private final ChangeTrackedLiveData> mLanguages; - private final ChangeTrackedLiveData> mAbilities; - private final ChangeTrackedLiveData> mActions; - private final ChangeTrackedLiveData> mReactions; - private final ChangeTrackedLiveData> mLairActions; - private final ChangeTrackedLiveData> mLegendaryActions; - private final ChangeTrackedLiveData> mRegionalActions; + private final ChangeTrackedLiveData> mDamageImmunities; + private final ChangeTrackedLiveData> mDamageResistances; + private final ChangeTrackedLiveData> mDamageVulnerabilities; + private final ChangeTrackedLiveData> mConditionImmunities; + private final ChangeTrackedLiveData> mLanguages; + private final ChangeTrackedLiveData> mAbilities; + private final ChangeTrackedLiveData> mActions; + private final ChangeTrackedLiveData> mReactions; + private final ChangeTrackedLiveData> mLairActions; + private final ChangeTrackedLiveData> mLegendaryActions; + private final ChangeTrackedLiveData> mRegionalActions; public EditMonsterViewModel() { + super(); mErrorMessage = new MutableLiveData<>(""); mHasError = new MutableLiveData<>(false); mHasLoaded = new MutableLiveData<>(false); - mHasChanges = new MutableLiveData<>(false); - ChangeTrackedLiveData.OnValueDirtiedCallback onDirtied = () -> mHasChanges.setValue(true); - mName = new ChangeTrackedLiveData<>("", onDirtied); - mMonsterId = new ChangeTrackedLiveData<>(UUID.randomUUID(), onDirtied); - mSize = new ChangeTrackedLiveData<>("", onDirtied); - mType = new ChangeTrackedLiveData<>("", onDirtied); - mSubtype = new ChangeTrackedLiveData<>("", onDirtied); - mAlignment = new ChangeTrackedLiveData<>("", onDirtied); - mCustomHitPoints = new ChangeTrackedLiveData<>("", onDirtied); - mHitDice = new ChangeTrackedLiveData<>(0, onDirtied); - mNaturalArmorBonus = new ChangeTrackedLiveData<>(0, onDirtied); - mHasCustomHitPoints = new ChangeTrackedLiveData<>(false, onDirtied); - mArmorType = new ChangeTrackedLiveData<>(ArmorType.NONE, onDirtied); - mHasShield = new ChangeTrackedLiveData<>(false, onDirtied); - mShieldBonus = new ChangeTrackedLiveData<>(0, onDirtied); - mCustomArmor = new ChangeTrackedLiveData<>("", onDirtied); - mWalkSpeed = new ChangeTrackedLiveData<>(0, onDirtied); - mBurrowSpeed = new ChangeTrackedLiveData<>(0, onDirtied); - mClimbSpeed = new ChangeTrackedLiveData<>(0, onDirtied); - mFlySpeed = new ChangeTrackedLiveData<>(0, onDirtied); - mSwimSpeed = new ChangeTrackedLiveData<>(0, onDirtied); - mCanHover = new ChangeTrackedLiveData<>(false, onDirtied); - mHasCustomSpeed = new ChangeTrackedLiveData<>(false, onDirtied); - mCustomSpeed = new ChangeTrackedLiveData<>("", onDirtied); - mStrength = new ChangeTrackedLiveData<>(10, onDirtied); - mDexterity = new ChangeTrackedLiveData<>(10, onDirtied); - mConstitution = new ChangeTrackedLiveData<>(10, onDirtied); - mIntelligence = new ChangeTrackedLiveData<>(10, onDirtied); - mWisdom = new ChangeTrackedLiveData<>(10, onDirtied); - mCharisma = new ChangeTrackedLiveData<>(10, onDirtied); - mStrengthProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mStrengthAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mDexterityProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mDexterityAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mConstitutionProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mConstitutionAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mIntelligenceProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mIntelligenceAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mWisdomProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mWisdomAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mCharismaProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mCharismaAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mChallengeRating = new ChangeTrackedLiveData<>(ChallengeRating.ONE_EIGHTH, onDirtied); - mCustomChallengeRatingDescription = new ChangeTrackedLiveData<>("", onDirtied); - mCustomProficiencyBonus = new ChangeTrackedLiveData<>(0, onDirtied); - mTelepathyRange = new ChangeTrackedLiveData<>(0, onDirtied); - mUnderstandsButDescription = new ChangeTrackedLiveData<>("", onDirtied); - mSkills = new ChangeTrackedLiveData<>(new ArrayList<>(), onDirtied); - mSenses = new ChangeTrackedLiveData<>(new ArrayList<>(), onDirtied); - mDamageImmunities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mDamageResistances = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mDamageVulnerabilities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mConditionImmunities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mLanguages = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mAbilities = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mActions = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mReactions = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mLairActions = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mLegendaryActions = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); - mRegionalActions = new ChangeTrackedLiveData<>(new HashSet<>(), onDirtied); + mName = new ChangeTrackedLiveData<>("", this::makeDirty); + mMonsterId = new ChangeTrackedLiveData<>(UUID.randomUUID(), this::makeDirty); + mSize = new ChangeTrackedLiveData<>("", this::makeDirty); + mType = new ChangeTrackedLiveData<>("", this::makeDirty); + mSubtype = new ChangeTrackedLiveData<>("", this::makeDirty); + mAlignment = new ChangeTrackedLiveData<>("", this::makeDirty); + mCustomHitPoints = new ChangeTrackedLiveData<>("", this::makeDirty); + mHitDice = new ChangeTrackedLiveData<>(0, this::makeDirty); + mNaturalArmorBonus = new ChangeTrackedLiveData<>(0, this::makeDirty); + mHasCustomHitPoints = new ChangeTrackedLiveData<>(false, this::makeDirty); + mArmorType = new ChangeTrackedLiveData<>(ArmorType.NONE, this::makeDirty); + mHasShield = new ChangeTrackedLiveData<>(false, this::makeDirty); + mShieldBonus = new ChangeTrackedLiveData<>(0, this::makeDirty); + mCustomArmor = new ChangeTrackedLiveData<>("", this::makeDirty); + mWalkSpeed = new ChangeTrackedLiveData<>(0, this::makeDirty); + mBurrowSpeed = new ChangeTrackedLiveData<>(0, this::makeDirty); + mClimbSpeed = new ChangeTrackedLiveData<>(0, this::makeDirty); + mFlySpeed = new ChangeTrackedLiveData<>(0, this::makeDirty); + mSwimSpeed = new ChangeTrackedLiveData<>(0, this::makeDirty); + mCanHover = new ChangeTrackedLiveData<>(false, this::makeDirty); + mHasCustomSpeed = new ChangeTrackedLiveData<>(false, this::makeDirty); + mCustomSpeed = new ChangeTrackedLiveData<>("", this::makeDirty); + mStrength = new ChangeTrackedLiveData<>(10, this::makeDirty); + mDexterity = new ChangeTrackedLiveData<>(10, this::makeDirty); + mConstitution = new ChangeTrackedLiveData<>(10, this::makeDirty); + mIntelligence = new ChangeTrackedLiveData<>(10, this::makeDirty); + mWisdom = new ChangeTrackedLiveData<>(10, this::makeDirty); + mCharisma = new ChangeTrackedLiveData<>(10, this::makeDirty); + mStrengthProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mStrengthAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mDexterityProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mDexterityAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mConstitutionProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mConstitutionAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mIntelligenceProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mIntelligenceAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mWisdomProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mWisdomAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mCharismaProficiency = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); + mCharismaAdvantage = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty); + mChallengeRating = new ChangeTrackedLiveData<>(ChallengeRating.ONE_EIGHTH, this::makeDirty); + mCustomChallengeRatingDescription = new ChangeTrackedLiveData<>("", this::makeDirty); + mCustomProficiencyBonus = new ChangeTrackedLiveData<>(0, this::makeDirty); + mTelepathyRange = new ChangeTrackedLiveData<>(0, this::makeDirty); + mUnderstandsButDescription = new ChangeTrackedLiveData<>("", this::makeDirty); + mSkills = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mSenses = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mDamageImmunities = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mDamageResistances = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mDamageVulnerabilities = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mConditionImmunities = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mLanguages = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mAbilities = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mActions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mReactions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mLairActions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mLegendaryActions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); + mRegionalActions = new ChangeTrackedLiveData<>(new ArrayList<>(), this::makeDirty); } public void copyFromMonster(Monster monster) { @@ -210,18 +208,28 @@ public class EditMonsterViewModel extends ViewModel { ArrayList senses = new ArrayList<>(monster.senses); Collections.sort(senses, String::compareToIgnoreCase); mSenses.resetValue(senses); - mDamageImmunities.resetValue(monster.damageImmunities); - mDamageResistances.resetValue(monster.damageResistances); - mDamageVulnerabilities.resetValue(monster.damageVulnerabilities); - mConditionImmunities.resetValue(monster.conditionImmunities); - mLanguages.resetValue(monster.languages); - mAbilities.resetValue(monster.abilities); - mActions.resetValue(monster.actions); - mReactions.resetValue(monster.reactions); - mLairActions.resetValue(monster.lairActions); - mLegendaryActions.resetValue(monster.legendaryActions); - mRegionalActions.resetValue(monster.regionalActions); - mHasChanges.setValue(false); + ArrayList damageImmunities = new ArrayList<>(monster.damageImmunities); + Collections.sort(damageImmunities, String::compareToIgnoreCase); + mDamageImmunities.resetValue(damageImmunities); + ArrayList damageResistances = new ArrayList<>(monster.damageResistances); + Collections.sort(damageResistances, String::compareToIgnoreCase); + mDamageResistances.resetValue(damageResistances); + ArrayList damageVulnerabilities = new ArrayList<>(monster.damageVulnerabilities); + Collections.sort(damageVulnerabilities, String::compareToIgnoreCase); + mDamageVulnerabilities.resetValue(damageVulnerabilities); + ArrayList conditionImmunities = new ArrayList<>(monster.conditionImmunities); + Collections.sort(conditionImmunities, String::compareToIgnoreCase); + mConditionImmunities.resetValue(conditionImmunities); + ArrayList languages = new ArrayList<>(monster.languages); + Collections.sort(languages, (lang1, lang2) -> lang1.getName().compareToIgnoreCase(lang2.getName())); + mLanguages.resetValue(languages); + mAbilities.resetValue(new ArrayList<>(monster.abilities)); + mActions.resetValue(new ArrayList<>(monster.actions)); + mReactions.resetValue(new ArrayList<>(monster.reactions)); + mLairActions.resetValue(new ArrayList<>(monster.lairActions)); + mLegendaryActions.resetValue(new ArrayList<>(monster.legendaryActions)); + mRegionalActions.resetValue(new ArrayList<>(monster.regionalActions)); + makeClean(); } public LiveData getName() { @@ -308,14 +316,6 @@ public class EditMonsterViewModel extends ViewModel { mCustomHitPoints.setValue(customHitPoints); } - public LiveData getHasChanges() { - return mHasChanges; - } - - public boolean hasChanges() { - return mHasChanges.getValue(); - } - public LiveData getHitDice() { return mHitDice; } @@ -756,13 +756,295 @@ public class EditMonsterViewModel extends ViewModel { return mSkills; } + public List getSkillsArray() { + return mSkills.getValue(); + } + + public Skill addNewSkill() { + Skill newSkill = new Skill("Unnamed Skill", AbilityScore.DEXTERITY); + ArrayList newSkills = new ArrayList<>(mSkills.getValue()); + newSkills.add(newSkill); + Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); + mSkills.setValue(newSkills); + return newSkill; + } + + public void removeSkill(int position) { + List skills = mSkills.getValue(); + ArrayList newSkills = new ArrayList<>(skills); + newSkills.remove(position); + mSkills.setValue(newSkills); + } + + public void replaceSkill(Skill newSkill, Skill oldSkill) { + List oldSkills = mSkills.getValue(); + if (oldSkills == null) { + oldSkills = new ArrayList<>(); + } + boolean hasReplaced = false; + ArrayList newSkills = new ArrayList<>(oldSkills.size()); + for (Skill skill : oldSkills) { + if (Objects.equals(skill, oldSkill)) { + newSkills.add(newSkill); + hasReplaced = true; + } else { + newSkills.add(skill); + } + } + if (!hasReplaced) { + newSkills.add(newSkill); + } + Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); + mSkills.setValue(newSkills); + } + + public LiveData> getSenses() { + return mSenses; + } + public List getSensesArray() { return mSenses.getValue(); } - // TODO: add getters and setters for lists of strings (Senses, Damage Immunities, Damage Resistances, Damage Vulnerabilities, and Condition Immunities) - // TODO: add getters and setters for Languages - // TODO: add getters and setters for traits (Abilities, Actions, Reactions, Lair Actions, Legendary Actions, and Regional Actions) + public String addNewSense() { + return Helpers.addItemToList(mSenses, "", String::compareToIgnoreCase); + } + + public void removeSense(int position) { + Helpers.removeFromList(mSenses, position); + } + + public void replaceSense(String oldSense, String newSense) { + Helpers.replaceItemInList(mSenses, oldSense, newSense, String::compareToIgnoreCase); + } + + public LiveData> getDamageImmunities() { + return mDamageImmunities; + } + + public List getDamageImmunitiesArray() { + return mDamageImmunities.getValue(); + } + + public String addNewDamageImmunity() { + return Helpers.addStringToList("", mDamageImmunities); + } + + public void removeDamageImmunity(int position) { + Helpers.removeFromList(mDamageImmunities, position); + } + + public void replaceDamageImmunity(String oldDamageType, String newDamageType) { + Helpers.replaceItemInList(mDamageImmunities, oldDamageType, newDamageType, String::compareToIgnoreCase); + } + + public LiveData> getDamageResistances() { + return mDamageResistances; + } + + public List getDamageResistancesArray() { + return mDamageResistances.getValue(); + } + + public String addNewDamageResistance() { + return Helpers.addStringToList("", mDamageResistances); + } + + public void removeDamageResistance(int position) { + Helpers.removeFromList(mDamageResistances, position); + } + + public void replaceDamageResistance(String oldDamageType, String newDamageType) { + Helpers.replaceItemInList(mDamageResistances, oldDamageType, newDamageType, String::compareToIgnoreCase); + } + + public LiveData> getDamageVulnerabilities() { + return mDamageVulnerabilities; + } + + public List getDamageVulnerabilitiesArray() { + return mDamageVulnerabilities.getValue(); + } + + public String addNewDamageVulnerability() { + return Helpers.addStringToList("", mDamageVulnerabilities); + } + + public void removeDamageVulnerability(int position) { + Helpers.removeFromList(mDamageVulnerabilities, position); + } + + public void replaceDamageVulnerability(String oldDamageType, String newDamageType) { + Helpers.replaceItemInList(mDamageVulnerabilities, oldDamageType, newDamageType, String::compareToIgnoreCase); + } + + public LiveData> getConditionImmunities() { + return mConditionImmunities; + } + + public List getConditionImmunitiesArray() { + return mConditionImmunities.getValue(); + } + + public String addNewConditionImmunity() { + return Helpers.addStringToList("", mConditionImmunities); + } + + public void removeConditionImmunity(int position) { + Helpers.removeFromList(mConditionImmunities, position); + } + + public void replaceConditionImmunity(String oldDamageType, String newDamageType) { + Helpers.replaceItemInList(mConditionImmunities, oldDamageType, newDamageType, String::compareToIgnoreCase); + } + + public LiveData> getLanguages() { + return mLanguages; + } + + public List getLanguagesArray() { + return mLanguages.getValue(); + } + + public Language addNewLanguage() { + Language newLanguage = new Language("", true); + return Helpers.addItemToList(mLanguages, newLanguage, Language::compareTo); + } + + public void removeLanguage(int position) { + Helpers.removeFromList(mLanguages, position); + } + + public void replaceLanguage(Language oldLanguage, Language newLanguage) { + Helpers.replaceItemInList(mLanguages, oldLanguage, newLanguage, Language::compareTo); + } + + public LiveData> getAbilities() { + return mAbilities; + } + + public List getAbilitiesArray() { + return mAbilities.getValue(); + } + + public Trait addNewAbility() { + Trait newAbility = new Trait("", ""); + return Helpers.addItemToList(mAbilities, newAbility, Trait::compareTo); + } + + public void removeAbility(int position) { + Helpers.removeFromList(mAbilities, position); + } + + public void replaceAbility(Trait oldAbility, Trait newAbility) { + Helpers.replaceItemInList(mAbilities, oldAbility, newAbility); + } + + + public LiveData> getActions() { + return mActions; + } + + public List getActionsArray() { + return mActions.getValue(); + } + + public Trait addNewAction() { + Trait newAction = new Trait("", ""); + return Helpers.addItemToList(mActions, newAction, Trait::compareTo); + } + + public void removeAction(int position) { + Helpers.removeFromList(mActions, position); + } + + public void replaceAction(Trait oldAction, Trait newAction) { + Helpers.replaceItemInList(mActions, oldAction, newAction); + } + + public LiveData> getReactions() { + return mReactions; + } + + public List getReactionsArray() { + return mReactions.getValue(); + } + + public Trait addNewReaction() { + Trait newReaction = new Trait("", ""); + return Helpers.addItemToList(mReactions, newReaction, Trait::compareTo); + } + + public void removeReaction(int position) { + Helpers.removeFromList(mReactions, position); + } + + public void replaceReaction(Trait oldReaction, Trait newReaction) { + Helpers.replaceItemInList(mReactions, oldReaction, newReaction); + } + + public LiveData> getLairActions() { + return mLairActions; + } + + public List getLairActionsArray() { + return mLairActions.getValue(); + } + + public Trait addNewLairAction() { + Trait newLairAction = new Trait("", ""); + return Helpers.addItemToList(mLairActions, newLairAction, Trait::compareTo); + } + + public void removeLairAction(int position) { + Helpers.removeFromList(mLairActions, position); + } + + public void replaceLairAction(Trait oldLairAction, Trait newLairAction) { + Helpers.replaceItemInList(mLairActions, oldLairAction, newLairAction); + } + + public LiveData> getLegendaryActions() { + return mLegendaryActions; + } + + public List getLegendaryActionsArray() { + return mLegendaryActions.getValue(); + } + + public Trait addNewLegendaryAction() { + Trait newLegendaryAction = new Trait("", ""); + return Helpers.addItemToList(mLegendaryActions, newLegendaryAction, Trait::compareTo); + } + + public void removeLegendaryAction(int position) { + Helpers.removeFromList(mLegendaryActions, position); + } + + public void replaceLegendaryAction(Trait oldLegendaryAction, Trait newLegendaryAction) { + Helpers.replaceItemInList(mLegendaryActions, oldLegendaryAction, newLegendaryAction); + } + + public LiveData> getRegionalActions() { + return mRegionalActions; + } + + public List getRegionalActionsArray() { + return mRegionalActions.getValue(); + } + + public Trait addNewRegionalAction() { + Trait newRegionalAction = new Trait("", ""); + return Helpers.addItemToList(mRegionalActions, newRegionalAction, Trait::compareTo); + } + + public void removeRegionalAction(int position) { + Helpers.removeFromList(mRegionalActions, position); + } + + public void replaceRegionalAction(Trait oldRegionalAction, Trait newRegionalAction) { + Helpers.replaceItemInList(mRegionalActions, oldRegionalAction, newRegionalAction); + } public Monster buildMonster() { Monster monster = new Monster(); @@ -813,60 +1095,99 @@ public class EditMonsterViewModel extends ViewModel { monster.understandsButDescription = mUnderstandsButDescription.getValue(); monster.skills = new HashSet<>(mSkills.getValue()); monster.senses = new HashSet<>(mSenses.getValue()); - monster.damageImmunities = mDamageImmunities.getValue(); - monster.damageResistances = mDamageResistances.getValue(); - monster.damageVulnerabilities = mDamageVulnerabilities.getValue(); - monster.conditionImmunities = mConditionImmunities.getValue(); - monster.languages = mLanguages.getValue(); - monster.abilities = mAbilities.getValue(); - monster.actions = mActions.getValue(); - monster.reactions = mReactions.getValue(); - monster.lairActions = mLairActions.getValue(); - monster.legendaryActions = mLegendaryActions.getValue(); - monster.regionalActions = mRegionalActions.getValue(); + monster.damageImmunities = new HashSet<>(mDamageImmunities.getValue()); + monster.damageResistances = new HashSet<>(mDamageResistances.getValue()); + monster.damageVulnerabilities = new HashSet<>(mDamageVulnerabilities.getValue()); + monster.conditionImmunities = new HashSet<>(mConditionImmunities.getValue()); + monster.languages = new HashSet<>(mLanguages.getValue()); + monster.abilities = new HashSet<>(mAbilities.getValue()); + monster.actions = new HashSet<>(mActions.getValue()); + monster.reactions = new HashSet<>(mReactions.getValue()); + monster.lairActions = new HashSet<>(mLairActions.getValue()); + monster.legendaryActions = new HashSet<>(mLegendaryActions.getValue()); + monster.regionalActions = new HashSet<>(mRegionalActions.getValue()); return monster; } - public List getSkillsArray() { - return mSkills.getValue(); - } - - public Skill addNewSkill() { - Skill newSkill = new Skill("Unnamed Skill", AbilityScore.DEXTERITY); - ArrayList newSkills = new ArrayList<>(mSkills.getValue()); - newSkills.add(newSkill); - Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); - mSkills.setValue(newSkills); - return newSkill; - } - - public void removeSkill(int position) { - List skills = mSkills.getValue(); - ArrayList newSkills = new ArrayList<>(skills); - newSkills.remove(position); - mSkills.setValue(newSkills); - } - - public void replaceSkill(Skill newSkill, Skill oldSkill) { - List oldSkills = mSkills.getValue(); - if (oldSkills == null) { - oldSkills = new ArrayList<>(); + @SuppressWarnings("SameParameterValue") + private static class Helpers { + static String addStringToList(String newString, MutableLiveData> strings) { + return addItemToList(strings, newString, String::compareToIgnoreCase); } - boolean hasReplaced = false; - ArrayList newSkills = new ArrayList<>(oldSkills.size()); - for (Skill skill : oldSkills) { - if (Objects.equals(skill, oldSkill)) { - newSkills.add(newSkill); - hasReplaced = true; - } else { - newSkills.add(skill); + + static T addItemToList(MutableLiveData> listData, T newItem, Comparator comparator) { + ArrayList newList = new ArrayList<>(listData.getValue()); + newList.add(newItem); + if (comparator != null) { + Collections.sort(newList, comparator); } + listData.setValue(newList); + return newItem; } - if (!hasReplaced) { - newSkills.add(newSkill); + + static void removeFromList(MutableLiveData> listData, int position) { + List oldList = listData.getValue(); + ArrayList newList = new ArrayList<>(oldList); + newList.remove(position); + listData.setValue(newList); + } + + static void replaceItemInList(MutableLiveData> listData, int position, T newItem, Comparator comparator) { + List oldList = listData.getValue(); + if (oldList == null) { + oldList = new ArrayList<>(); + } + int size = oldList.size(); + boolean hasReplaced = false; + ArrayList newList = new ArrayList<>(size); + for (int index = 0; index < size; index++) { + if (index == position) { + newList.add(newItem); + hasReplaced = true; + } else { + newList.add(oldList.get(index)); + } + } + if (!hasReplaced) { + newList.add(newItem); + } + if (comparator != null) { + Collections.sort(newList, comparator); + } + listData.setValue(newList); + } + + static void replaceItemInList(MutableLiveData> listData, int position, T newItem) { + replaceItemInList(listData, position, newItem, null); + } + + static void replaceItemInList(MutableLiveData> listData, T oldItem, T newItem, Comparator comparator) { + List oldList = listData.getValue(); + if (oldList == null) { + oldList = new ArrayList<>(); + } + boolean hasReplaced = false; + ArrayList newList = new ArrayList<>(oldList.size()); + for (T item : oldList) { + if (Objects.equals(item, oldItem)) { + newList.add(newItem); + hasReplaced = true; + } else { + newList.add(item); + } + } + if (!hasReplaced) { + newList.add(newItem); + } + if (comparator != null) { + Collections.sort(newList, comparator); + } + listData.setValue(newList); + } + + static void replaceItemInList(MutableLiveData> listData, T oldItem, T newItem) { + replaceItemInList(listData, oldItem, newItem, null); } - Collections.sort(newSkills, (skill1, skill2) -> skill1.name.compareToIgnoreCase(skill2.name)); - mSkills.setValue(newSkills); } } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSavingThrowsFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSavingThrowsFragment.java index c1a0f76..e66fe9d 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSavingThrowsFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSavingThrowsFragment.java @@ -14,6 +14,7 @@ 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 Fragment { private EditMonsterViewModel mViewModel; diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java new file mode 100644 index 0000000..4d99588 --- /dev/null +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java @@ -0,0 +1,77 @@ +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.ui.shared.MCFragment; +import com.majinnaibu.monstercards.utils.Logger; +import com.majinnaibu.monstercards.utils.TextChangedListener; + +public class EditSenseFragment extends MCFragment { + private EditMonsterViewModel mEditMonsterViewModel; + private EditStringViewModel mViewModel; + private ViewHolder mHolder; + private String mOldSense; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + mViewModel = new ViewModelProvider(this).get(EditStringViewModel.class); + if (getArguments() != null) { + EditSenseFragmentArgs args = EditSenseFragmentArgs.fromBundle(getArguments()); + mOldSense = args.getSense(); + mViewModel.resetValue(mOldSense); + } else { + Logger.logWTF("EditSenseFragment needs arguments"); + mOldSense = 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_sense, container, false); + + mHolder = new ViewHolder(root); + + 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.replaceSense(mOldSense, mViewModel.getValueAsString()); + } + Navigation.findNavController(requireView()).navigateUp(); + } + }); + + return root; + } + + private static class ViewHolder { + EditText description; + + ViewHolder(View root) { + description = root.findViewById(R.id.name); + } + } + +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java new file mode 100644 index 0000000..5c7482a --- /dev/null +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java @@ -0,0 +1,92 @@ +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.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 EditSensesFragment extends MCFragment { + private EditMonsterViewModel mViewModel; + private ViewHolder mHolder; + + private void navigateToEditSense(String sense) { + NavDirections action = EditSensesFragmentDirections.actionEditSensesFragmentToEditSenseFragment(sense); + View view = getView(); + assert view != null; + Navigation.findNavController(view).navigate(action); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment); + NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation); + mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class); + View root = inflater.inflate(R.layout.fragment_edit_senses_list, container, false); + mHolder = new ViewHolder(root); + setupRecyclerView(mHolder.list); + setupAddSenseButton(mHolder.addSense); + return root; + } + + private void setupRecyclerView(@NonNull RecyclerView recyclerView) { + Context context = requireContext(); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + recyclerView.setLayoutManager(layoutManager); + + mViewModel.getSenses().observe(getViewLifecycleOwner(), senses -> { + EditSensesRecyclerViewAdapter adapter = new EditSensesRecyclerViewAdapter(mViewModel.getSensesArray(), sense -> { + if (sense != null) { + navigateToEditSense(sense); + } else { + Logger.logError("Can't navigate to EditSense with a null sense"); + } + }); + recyclerView.setAdapter(adapter); + }); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation()); + recyclerView.addItemDecoration(dividerItemDecoration); + + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, mViewModel::removeSense)); + itemTouchHelper.attachToRecyclerView(recyclerView); + } + + private void setupAddSenseButton(@NonNull FloatingActionButton fab) { + fab.setOnClickListener(view -> { + String newSense = mViewModel.addNewSense(); + navigateToEditSense(newSense); + }); + } + + private static class ViewHolder { + RecyclerView list; + FloatingActionButton addSense; + + ViewHolder(View root) { + list = root.findViewById(R.id.list); + addSense = root.findViewById(R.id.add_sense); + } + } +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillFragment.java index 1eb08dc..c744460 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillFragment.java @@ -20,6 +20,7 @@ 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; @@ -37,7 +38,7 @@ public class EditSkillFragment extends Fragment { mViewModel.copyFromSkill(args.getName(), args.getAbilityScore(), args.getProficiency(), args.getAdvantage()); mOldSkill = new Skill(args.getName(), args.getAbilityScore(), args.getAdvantage(), args.getProficiency()); } else { - Logger.logWTF("This should never happen. EditSkillFragment needs arguments."); + Logger.logWTF("EditSkillFragment needs arguments."); mOldSkill = null; } super.onCreate(savedInstanceState); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillViewModel.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillViewModel.java index 1d33390..6af3d26 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillViewModel.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillViewModel.java @@ -1,43 +1,28 @@ package com.majinnaibu.monstercards.ui.editmonster; import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; 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 ViewModel { +public class EditSkillViewModel extends ChangeTrackedViewModel { private final ChangeTrackedLiveData mAbilityScore; private final ChangeTrackedLiveData mAdvantageType; - private final MutableLiveData mHasChanges; private final ChangeTrackedLiveData mProficiencyType; private final ChangeTrackedLiveData mName; private final ChangeTrackedLiveData mSkill; public EditSkillViewModel() { - mHasChanges = new MutableLiveData<>(false); - ChangeTrackedLiveData.OnValueDirtiedCallback onDirtied = () -> mHasChanges.setValue(true); - - mAbilityScore = new ChangeTrackedLiveData<>(AbilityScore.STRENGTH, onDirtied); - mAdvantageType = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied); - mProficiencyType = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied); - mName = new ChangeTrackedLiveData<>("Unknown Skill", onDirtied); - mSkill = new ChangeTrackedLiveData<>(makeSkill(), onDirtied); - } - - public EditSkillViewModel(Skill skill) { - mHasChanges = new MutableLiveData<>(false); - ChangeTrackedLiveData.OnValueDirtiedCallback onDirtied = () -> mHasChanges.setValue(true); - - mAbilityScore = new ChangeTrackedLiveData<>(skill.abilityScore, onDirtied); - mAdvantageType = new ChangeTrackedLiveData<>(skill.advantageType, onDirtied); - mProficiencyType = new ChangeTrackedLiveData<>(skill.proficiencyType, onDirtied); - mName = new ChangeTrackedLiveData<>(skill.name, onDirtied); - mSkill = new ChangeTrackedLiveData<>(makeSkill(), onDirtied); + 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<>("Unknown Skill", this::makeDirty); + mSkill = new ChangeTrackedLiveData<>(makeSkill(), this::makeDirty); } public void copyFromSkill(Skill skill) { @@ -47,13 +32,6 @@ public class EditSkillViewModel extends ViewModel { mName.resetValue(skill.name); } - public void copyFromSkill(String name, AbilityScore abilityScore, ProficiencyType proficiency, AdvantageType advantage) { - mAbilityScore.resetValue(abilityScore); - mAdvantageType.resetValue(advantage); - mProficiencyType.resetValue(proficiency); - mName.resetValue(name); - } - public LiveData getSkill() { return mSkill; } @@ -94,14 +72,6 @@ public class EditSkillViewModel extends ViewModel { mSkill.setValue(makeSkill()); } - public LiveData getHasChanges() { - return mHasChanges; - } - - public boolean hasChanges() { - return mHasChanges.getValue(); - } - private Skill makeSkill() { return new Skill(mName.getValue(), mAbilityScore.getValue(), mAdvantageType.getValue(), mProficiencyType.getValue()); } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillsFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillsFragment.java index 13de066..608896f 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillsFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSkillsFragment.java @@ -7,7 +7,6 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavController; @@ -21,14 +20,14 @@ 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. */ -@SuppressWarnings("FieldCanBeLocal") -public class EditSkillsFragment extends Fragment { +public class EditSkillsFragment extends MCFragment { private EditMonsterViewModel mViewModel; private ViewHolder mHolder; @@ -67,7 +66,7 @@ public class EditSkillsFragment extends Fragment { } else { Logger.logError("Can't navigate to EditSkill with a null skill"); } - }, null); + }); recyclerView.setAdapter(adapter); }); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java index 0cf820e..8d53f8a 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSpeedFragment.java @@ -15,6 +15,7 @@ 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 Fragment { diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringFragment.java index 54e4ee4..4a37439 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringFragment.java @@ -9,49 +9,45 @@ import android.widget.EditText; import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; 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 { +public class EditConditionImmunityFragment extends Fragment { 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(); + EditConditionImmunityFragmentArgs args = EditConditionImmunityFragmentArgs.fromBundle(getArguments()); + mOldValue = args.getCondition(); + mViewModel.resetValue(mOldValue); } else { - Logger.logWTF("EditStringFragment needs arguments"); + Logger.logWTF("EditConditionImmunityFragment needs arguments"); mOldValue = null; } + super.onCreate(savedInstanceState); } - @Nullable @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + 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); + View root = inflater.inflate(R.layout.fragment_edit_condition_immunity, 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()))); @@ -59,7 +55,7 @@ public class EditStringFragment extends MCFragment { @Override public void handleOnBackPressed() { if (mViewModel.hasChanges()) { - mEditMonsterViewModel.replaceString(mStringType, mOldValue, mViewModel.getValueAsString()); + mEditMonsterViewModel.replaceConditionImmunity(mOldValue, mViewModel.getValueAsString()); } Navigation.findNavController(requireView()).navigateUp(); } @@ -68,35 +64,11 @@ public class EditStringFragment extends MCFragment { 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) { + ViewHolder(View root) { description = root.findViewById(R.id.description); } } -} +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsRecyclerViewAdapter.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsRecyclerViewAdapter.java index fda532c..a0cc370 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsRecyclerViewAdapter.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditStringsRecyclerViewAdapter.java @@ -4,30 +4,34 @@ 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 com.majinnaibu.monstercards.databinding.FragmentEditConditionImmunitiesListItemBinding; + +import org.jetbrains.annotations.NotNull; import java.util.List; -public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter { +/** + * {@link RecyclerView.Adapter} that can display a {@link String}. + */ +public class EditConditionImmunitiesRecyclerViewAdapter extends RecyclerView.Adapter { private final List mValues; private final ItemCallback mOnClick; - public EditStringsRecyclerViewAdapter(List items, ItemCallback onClick) { + public EditConditionImmunitiesRecyclerViewAdapter(List items, ItemCallback onClick) { mValues = items; mOnClick = onClick; } - @NonNull + @NotNull @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new ViewHolder(FragmentEditStringsListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + public ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) { + return new ViewHolder(FragmentEditConditionImmunitiesListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); } @Override - public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { + public void onBindViewHolder(final ViewHolder holder, int position) { holder.mItem = mValues.get(position); holder.mContentView.setText(mValues.get(position)); holder.itemView.setOnClickListener(v -> { @@ -43,22 +47,22 @@ public class EditStringsRecyclerViewAdapter extends RecyclerView.Adapter { - repository - .deleteMonster(monster) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(() -> { - Logger.logDebug("deleted"); - }, Logger::logError); - }, - mTwoPane); + (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); - recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(getContext(), (position) -> { - adapter.deleteItem(position); - })); + + 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(), adapter::deleteItem)); itemTouchHelper.attachToRecyclerView(recyclerView); } private void setupAddMonsterButton(@NonNull FloatingActionButton fab) { fab.setOnClickListener(view -> { Monster monster = new Monster(); - monster.name = "Unnamed Monster"; + monster.name = getString(R.string.default_monster_name); MonsterRepository repository = this.getMonsterRepository(); repository.addMonster(monster) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(() -> { - Snackbar.make( - getView(), - String.format("%s created", monster.name), - Snackbar.LENGTH_LONG) - .setAction("Action", (_view) -> { - navigateToMonsterDetail(monster.id); - }) - .show(); - }, throwable -> { - Logger.logError("Error creating monster", throwable); - Snackbar.make(getView(), "Failed to create monster", Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); - }); - }); + .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(UUID monsterId) { NavDirections action = LibraryFragmentDirections.actionNavigationLibraryToNavigationMonster(monsterId.toString()); - Navigation.findNavController(getView()).navigate(action); + View view = getView(); + assert view != null; + Navigation.findNavController(view).navigate(action); } } diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java index 32145c1..cf0031d 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/monster/MonsterDetailFragment.java @@ -26,7 +26,7 @@ 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.MCFragment; +import com.majinnaibu.monstercards.ui.shared.MCFragment; import com.majinnaibu.monstercards.utils.Logger; import java.util.UUID; @@ -241,10 +241,15 @@ public class MonsterDetailFragment extends MCFragment { @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { if (item.getItemId() == R.id.menu_action_edit_monster) { - NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterDetailViewModel.getId().toString()); - View view = getView(); - assert view != null; - Navigation.findNavController(view).navigate(action); + UUID monsterId = monsterDetailViewModel.getId().getValue(); + if (monsterId != null) { + NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterId.toString()); + View view = getView(); + assert view != null; + Navigation.findNavController(view).navigate(action); + } else { + Logger.logWTF("monsterId cannot be null."); + } return true; } return super.onOptionsItemSelected(item); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java index b25276c..12ab602 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchFragment.java @@ -14,12 +14,10 @@ import androidx.recyclerview.widget.RecyclerView; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.data.MonsterRepository; -import com.majinnaibu.monstercards.ui.MCFragment; +import com.majinnaibu.monstercards.ui.shared.MCFragment; public class SearchFragment extends MCFragment { - private SearchViewModel searchViewModel; - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_search, container, false); diff --git a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java index c437486..c9f62e2 100644 --- a/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java +++ b/Android/app/src/main/java/com/majinnaibu/monstercards/ui/search/SearchResultsRecyclerViewAdapter.java @@ -13,6 +13,8 @@ import com.majinnaibu.monstercards.data.MonsterRepository; import com.majinnaibu.monstercards.models.Monster; import com.majinnaibu.monstercards.utils.Logger; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.List; @@ -20,16 +22,11 @@ import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.disposables.Disposable; public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter { - public interface ItemCallback { - void onItem(Monster monster); - } - private final MonsterRepository mRepository; + private final ItemCallback mOnClickHandler; private String mSearchText; private List mValues; private Disposable mSubscriptionHandler; - private final ItemCallback mOnClickHandler; - public SearchResultsRecyclerViewAdapter(MonsterRepository repository, ItemCallback onClick) { mRepository = repository; @@ -54,6 +51,7 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter Logger.logError("Error performing search", throwable)); } + @NotNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) @@ -79,7 +77,11 @@ public class SearchResultsRecyclerViewAdapter extends RecyclerView.Adapter