diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java new file mode 100644 index 0000000..ba12084 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesFragment.java @@ -0,0 +1,96 @@ +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. + */ +@SuppressWarnings("FieldCanBeLocal") +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/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesRecyclerViewAdapter.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesRecyclerViewAdapter.java new file mode 100644 index 0000000..a3336e0 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunitiesRecyclerViewAdapter.java @@ -0,0 +1,68 @@ +package com.majinnaibu.monstercards.ui.editmonster; + +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.majinnaibu.monstercards.databinding.FragmentEditConditionImmunitiesListItemBinding; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * {@link RecyclerView.Adapter} that can display a {@link String}. + */ +public class EditConditionImmunitiesRecyclerViewAdapter extends RecyclerView.Adapter { + private final List mValues; + private final ItemCallback mOnClick; + + public EditConditionImmunitiesRecyclerViewAdapter(List items, ItemCallback onClick) { + mValues = items; + mOnClick = onClick; + } + + @NotNull + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(FragmentEditConditionImmunitiesListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(final ViewHolder holder, int position) { + holder.mItem = mValues.get(position); + holder.mContentView.setText(mValues.get(position)); + holder.itemView.setOnClickListener(v -> { + if (mOnClick != null) { + mOnClick.onItemCallback(holder.mItem); + } + }); + } + + @Override + public int getItemCount() { + return mValues.size(); + } + + public interface ItemCallback { + void onItemCallback(String condition); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + public final TextView mContentView; + public String mItem; + + public ViewHolder(FragmentEditConditionImmunitiesListItemBinding binding) { + super(binding.getRoot()); + mContentView = binding.content; + } + + @NotNull + @Override + public String toString() { + return super.toString() + " '" + mContentView.getText() + "'"; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityFragment.java new file mode 100644 index 0000000..2c68c6b --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityFragment.java @@ -0,0 +1,75 @@ +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.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.utils.Logger; +import com.majinnaibu.monstercards.utils.TextChangedListener; + +@SuppressWarnings("FieldCanBeLocal") +public class EditConditionImmunityFragment extends Fragment { + private EditMonsterViewModel mEditMonsterViewModel; + private EditConditionImmunityViewModel mViewModel; + private ViewHolder mHolder; + private String mOldValue; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + mViewModel = new ViewModelProvider(this).get(EditConditionImmunityViewModel.class); + if (getArguments() != null) { + EditConditionImmunityFragmentArgs args = EditConditionImmunityFragmentArgs.fromBundle(getArguments()); + mOldValue = args.getCondition(); + mViewModel.reset(mOldValue); + } else { + Logger.logWTF("This should never happen. EditConditionImmunityFragment needs arguments"); + mOldValue = 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_condition_immunity, container, false); + mHolder = new ViewHolder(root); + mHolder.description.setText(mViewModel.getDescription().getValue()); + mHolder.description.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setDescription(s.toString()))); + + requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (mViewModel.hasChanges()) { + mEditMonsterViewModel.replaceConditionImmunity(mOldValue, mViewModel.getDescription().getValue()); + } + Navigation.findNavController(requireView()).navigateUp(); + } + }); + + return root; + } + + private static class ViewHolder { + EditText description; + + ViewHolder(View root) { + description = root.findViewById(R.id.description); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityViewModel.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityViewModel.java new file mode 100644 index 0000000..2d311f1 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditConditionImmunityViewModel.java @@ -0,0 +1,36 @@ +package com.majinnaibu.monstercards.ui.editmonster; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData; + +public class EditConditionImmunityViewModel extends ViewModel { + private final ChangeTrackedLiveData mDescription; + private final MutableLiveData mHasChanges; + + public EditConditionImmunityViewModel() { + mHasChanges = new MutableLiveData<>(false); + ChangeTrackedLiveData.OnValueDirtiedCallback onDirtied = () -> mHasChanges.setValue(true); + mDescription = new ChangeTrackedLiveData<>("", onDirtied); + } + + public void reset(String description) { + mHasChanges.setValue(false); + mDescription.resetValue(description); + } + + public LiveData getDescription() { + return mDescription; + } + + public void setDescription(String description) { + mDescription.setValue(description); + } + + public boolean hasChanges() { + Boolean value = mHasChanges.getValue(); + return value != null && value; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java index 7d43eab..93254ff 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditMonsterFragment.java @@ -121,6 +121,11 @@ public class EditMonsterFragment extends MCFragment { Navigation.findNavController(requireView()).navigate(action); }); + mHolder.conditionImmunities.setOnClickListener(v -> { + NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditConditionImmunitiesFragment(); + Navigation.findNavController(requireView()).navigate(action); + }); + requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java index 423353a..58524af 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseFragment.java @@ -19,6 +19,7 @@ import com.majinnaibu.monstercards.ui.MCFragment; import com.majinnaibu.monstercards.utils.Logger; import com.majinnaibu.monstercards.utils.TextChangedListener; +@SuppressWarnings("FieldCanBeLocal") public class EditSenseFragment extends MCFragment { private EditMonsterViewModel mEditMonsterViewModel; private EditSenseViewModel mViewModel; @@ -26,12 +27,12 @@ public class EditSenseFragment extends MCFragment { private String mOldSense; @Override - public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { + public void onCreate(@Nullable Bundle savedInstanceState) { mViewModel = new ViewModelProvider(this).get(EditSenseViewModel.class); if (getArguments() != null) { EditSenseFragmentArgs args = EditSenseFragmentArgs.fromBundle(getArguments()); mOldSense = args.getSense(); - mViewModel.copyFromSense(mOldSense); + mViewModel.reset(mOldSense); } else { Logger.logWTF("This should never happen. EditSenseFragment needs arguments"); mOldSense = null; diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseViewModel.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseViewModel.java index 6250819..a7e4d65 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseViewModel.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSenseViewModel.java @@ -16,8 +16,9 @@ public class EditSenseViewModel extends ViewModel { mDescription = new ChangeTrackedLiveData<>("", onDirtied); } - public void copyFromSense(String sense) { - mDescription.resetValue(sense); + public void reset(String description) { + mHasChanges.setValue(false); + mDescription.resetValue(description); } public LiveData getDescription() { diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java index b2669a8..2a818b8 100644 --- a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/EditSensesFragment.java @@ -44,13 +44,10 @@ public class EditSensesFragment extends MCFragment { 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; } @@ -89,8 +86,8 @@ public class EditSensesFragment extends MCFragment { FloatingActionButton addSense; ViewHolder(View root) { - this.list = root.findViewById(R.id.list); - this.addSense = root.findViewById(R.id.add_sense); + list = root.findViewById(R.id.list); + addSense = root.findViewById(R.id.add_sense); } } } \ No newline at end of file diff --git a/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/placeholder/PlaceholderContent.java b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/placeholder/PlaceholderContent.java new file mode 100644 index 0000000..d6519c6 --- /dev/null +++ b/app/src/main/java/com/majinnaibu/monstercards/ui/editmonster/placeholder/PlaceholderContent.java @@ -0,0 +1,72 @@ +package com.majinnaibu.monstercards.ui.editmonster.placeholder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Helper class for providing sample content for user interfaces created by + * Android template wizards. + *

+ * TODO: Replace all uses of this class before publishing your app. + */ +public class PlaceholderContent { + + /** + * An array of sample (placeholder) items. + */ + public static final List ITEMS = new ArrayList(); + + /** + * A map of sample (placeholder) items, by ID. + */ + public static final Map ITEM_MAP = new HashMap(); + + private static final int COUNT = 25; + + static { + // Add some sample items. + for (int i = 1; i <= COUNT; i++) { + addItem(createPlaceholderItem(i)); + } + } + + private static void addItem(PlaceholderItem item) { + ITEMS.add(item); + ITEM_MAP.put(item.id, item); + } + + private static PlaceholderItem createPlaceholderItem(int position) { + return new PlaceholderItem(String.valueOf(position), "Item " + position, makeDetails(position)); + } + + private static String makeDetails(int position) { + StringBuilder builder = new StringBuilder(); + builder.append("Details about Item: ").append(position); + for (int i = 0; i < position; i++) { + builder.append("\nMore details information here."); + } + return builder.toString(); + } + + /** + * A placeholder item representing a piece of content. + */ + public static class PlaceholderItem { + public final String id; + public final String content; + public final String details; + + public PlaceholderItem(String id, String content, String details) { + this.id = id; + this.content = content; + this.details = details; + } + + @Override + public String toString() { + return content; + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_edit_condition_immunities_list.xml b/app/src/main/res/layout/fragment_edit_condition_immunities_list.xml new file mode 100644 index 0000000..55df7b8 --- /dev/null +++ b/app/src/main/res/layout/fragment_edit_condition_immunities_list.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_edit_condition_immunities_list_item.xml b/app/src/main/res/layout/fragment_edit_condition_immunities_list_item.xml new file mode 100644 index 0000000..6e9049a --- /dev/null +++ b/app/src/main/res/layout/fragment_edit_condition_immunities_list_item.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_edit_condition_immunity.xml b/app/src/main/res/layout/fragment_edit_condition_immunity.xml new file mode 100644 index 0000000..49aba4b --- /dev/null +++ b/app/src/main/res/layout/fragment_edit_condition_immunity.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index 9840cf6..72089fb 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -96,6 +96,9 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 67cd8fb..08ad2fe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,6 +2,7 @@ Add monster Add Sense Add Skill + Add Condition Edit Actions MonsterCards