Adds OnMoveCallback to the SwipeToDeleteCallback class.
Makes traits orderable.
This commit is contained in:
@@ -7,23 +7,22 @@ import androidx.room.TypeConverters;
|
||||
import com.majinnaibu.monstercards.data.MonsterDAO;
|
||||
import com.majinnaibu.monstercards.data.converters.ArmorTypeConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.ChallengeRatingConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.ListOfTraitsConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfLanguageConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfSkillConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfStringConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.SetOfTraitConverter;
|
||||
import com.majinnaibu.monstercards.data.converters.UUIDConverter;
|
||||
import com.majinnaibu.monstercards.models.Monster;
|
||||
import com.majinnaibu.monstercards.models.MonsterFTS;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Database(entities = {Monster.class, MonsterFTS.class}, version = 3)
|
||||
@TypeConverters({
|
||||
ArmorTypeConverter.class,
|
||||
ChallengeRatingConverter.class,
|
||||
ListOfTraitsConverter.class,
|
||||
SetOfLanguageConverter.class,
|
||||
SetOfSkillConverter.class,
|
||||
SetOfStringConverter.class,
|
||||
SetOfTraitConverter.class,
|
||||
UUIDConverter.class,
|
||||
})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
@@ -7,20 +7,20 @@ import com.google.gson.reflect.TypeToken;
|
||||
import com.majinnaibu.monstercards.models.Trait;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SetOfTraitConverter {
|
||||
public class ListOfTraitsConverter {
|
||||
@TypeConverter
|
||||
public static String fromSetOfTrait(Set<Trait> traits) {
|
||||
public static String fromListOfTraits(List<Trait> traits) {
|
||||
Gson gson = new Gson();
|
||||
return gson.toJson(traits);
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
public static Set<Trait> setOfTraitFromString(String string) {
|
||||
public static List<Trait> listOfTraitsFromString(String string) {
|
||||
Gson gson = new Gson();
|
||||
Type setType = new TypeToken<HashSet<Trait>>() {
|
||||
Type setType = new TypeToken<ArrayList<Trait>>() {
|
||||
}.getType();
|
||||
return gson.fromJson(string, setType);
|
||||
}
|
||||
@@ -187,22 +187,22 @@ public class Monster {
|
||||
public Set<Language> languages;
|
||||
|
||||
@ColumnInfo(name = "abilities", defaultValue = "[]")
|
||||
public Set<Trait> abilities;
|
||||
public List<Trait> abilities;
|
||||
|
||||
@ColumnInfo(name = "actions", defaultValue = "[]")
|
||||
public Set<Trait> actions;
|
||||
public List<Trait> actions;
|
||||
|
||||
@ColumnInfo(name = "reactions", defaultValue = "[]")
|
||||
public Set<Trait> reactions;
|
||||
public List<Trait> reactions;
|
||||
|
||||
@ColumnInfo(name = "lair_actions", defaultValue = "[]")
|
||||
public Set<Trait> lairActions;
|
||||
public List<Trait> lairActions;
|
||||
|
||||
@ColumnInfo(name = "legendary_actions", defaultValue = "[]")
|
||||
public Set<Trait> legendaryActions;
|
||||
public List<Trait> legendaryActions;
|
||||
|
||||
@ColumnInfo(name = "regional_actions", defaultValue = "[]")
|
||||
public Set<Trait> regionalActions;
|
||||
public List<Trait> regionalActions;
|
||||
|
||||
public Monster() {
|
||||
id = UUID.randomUUID();
|
||||
@@ -258,12 +258,12 @@ public class Monster {
|
||||
damageVulnerabilities = new HashSet<>();
|
||||
conditionImmunities = new HashSet<>();
|
||||
languages = new HashSet<>();
|
||||
abilities = new HashSet<>();
|
||||
actions = new HashSet<>();
|
||||
reactions = new HashSet<>();
|
||||
lairActions = new HashSet<>();
|
||||
legendaryActions = new HashSet<>();
|
||||
regionalActions = new HashSet<>();
|
||||
abilities = new ArrayList<>();
|
||||
actions = new ArrayList<>();
|
||||
reactions = new ArrayList<>();
|
||||
lairActions = new ArrayList<>();
|
||||
legendaryActions = new ArrayList<>();
|
||||
regionalActions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static int getAbilityModifierForScore(int score) {
|
||||
|
||||
@@ -75,11 +75,11 @@ public class EditLanguagesFragment extends MCFragment {
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, position -> {
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> {
|
||||
if (position > 0) {
|
||||
mViewModel.removeLanguage(position - 1);
|
||||
}
|
||||
}));
|
||||
}, null));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
|
||||
@@ -992,12 +992,12 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
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());
|
||||
monster.abilities = new ArrayList<>(mAbilities.getValue());
|
||||
monster.actions = new ArrayList<>(mActions.getValue());
|
||||
monster.reactions = new ArrayList<>(mReactions.getValue());
|
||||
monster.lairActions = new ArrayList<>(mLairActions.getValue());
|
||||
monster.legendaryActions = new ArrayList<>(mLegendaryActions.getValue());
|
||||
monster.regionalActions = new ArrayList<>(mRegionalActions.getValue());
|
||||
|
||||
return monster;
|
||||
}
|
||||
@@ -1176,12 +1176,30 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static class Helpers {
|
||||
static String addStringToList(String newString, MutableLiveData<List<String>> strings) {
|
||||
return addItemToList(strings, newString, String::compareToIgnoreCase);
|
||||
public boolean moveTrait(TraitType type, int from, int to) {
|
||||
switch (type) {
|
||||
case ABILITY:
|
||||
return Helpers.moveItemInList(mAbilities, from, to);
|
||||
case ACTION:
|
||||
return Helpers.moveItemInList(mActions, from, to);
|
||||
case LAIR_ACTION:
|
||||
return Helpers.moveItemInList(mLairActions, from, to);
|
||||
case LEGENDARY_ACTION:
|
||||
return Helpers.moveItemInList(mLegendaryActions, from, to);
|
||||
case REACTIONS:
|
||||
return Helpers.moveItemInList(mReactions, from, to);
|
||||
case REGIONAL_ACTION:
|
||||
return Helpers.moveItemInList(mRegionalActions, from, to);
|
||||
default:
|
||||
Logger.logUnimplementedFeature(String.format("Unrecognized TraitType: %s", type));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static class Helpers {
|
||||
static <T> T addItemToList(MutableLiveData<List<T>> listData, T newItem) {
|
||||
return addItemToList(listData, newItem, null);
|
||||
}
|
||||
@@ -1228,6 +1246,7 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
listData.setValue(newList);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static <T> void replaceItemInList(MutableLiveData<List<T>> listData, int position, T newItem) {
|
||||
replaceItemInList(listData, position, newItem, null);
|
||||
}
|
||||
@@ -1266,5 +1285,23 @@ public class EditMonsterViewModel extends ChangeTrackedViewModel {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static <T> boolean moveItemInList(ChangeTrackedLiveData<List<T>> listData, int from, int to) {
|
||||
List<T> oldList = listData.getValue();
|
||||
if (oldList == null) {
|
||||
oldList = new ArrayList<>();
|
||||
}
|
||||
ArrayList<T> newList = new ArrayList<>(oldList);
|
||||
T item = oldList.get(from);
|
||||
if (from > to) {
|
||||
from = from + 1;
|
||||
} else if (to > from) {
|
||||
to = to + 1;
|
||||
}
|
||||
newList.add(to, item);
|
||||
newList.remove(from);
|
||||
listData.setValue(newList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class EditSkillsFragment extends MCFragment {
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, mViewModel::removeSkill));
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeSkill(position), null));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ public class EditStringsFragment extends MCFragment {
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, position -> mViewModel.removeString(mStringType, position)));
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeString(mStringType, position), null));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public class EditTraitsFragment extends MCFragment {
|
||||
private EditMonsterViewModel mViewModel;
|
||||
private ViewHolder mHolder;
|
||||
private TraitType mTraitType;
|
||||
private EditTraitsRecyclerViewAdapter mAdapter;
|
||||
|
||||
|
||||
@Override
|
||||
@@ -88,22 +89,21 @@ public class EditTraitsFragment extends MCFragment {
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
|
||||
LiveData<List<Trait>> traitData = mViewModel.getTraits(mTraitType);
|
||||
mAdapter = new EditTraitsRecyclerViewAdapter(trait -> {
|
||||
if (trait != null) {
|
||||
navigateToEditTrait(trait);
|
||||
} else {
|
||||
Logger.logError("Can't navigate to EditTraitFragment with a null trait");
|
||||
}
|
||||
});
|
||||
if (traitData != null) {
|
||||
traitData.observe(getViewLifecycleOwner(), traits -> {
|
||||
EditTraitsRecyclerViewAdapter adapter = new EditTraitsRecyclerViewAdapter(traits, trait -> {
|
||||
if (trait != null) {
|
||||
navigateToEditTrait(trait);
|
||||
} else {
|
||||
Logger.logError("Can't navigate to EditTraitFragment with a null trait");
|
||||
}
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
});
|
||||
traitData.observe(getViewLifecycleOwner(), traits -> mAdapter.submitList(traits));
|
||||
}
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, position -> mViewModel.removeTrait(mTraitType, position)));
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, (position, direction) -> mViewModel.removeTrait(mTraitType, position), (from, to) -> mViewModel.moveTrait(mTraitType, from, to)));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.ListAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.majinnaibu.monstercards.databinding.FragmentEditTraitsListItemBinding;
|
||||
@@ -11,14 +14,23 @@ import com.majinnaibu.monstercards.models.Trait;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
public class EditTraitsRecyclerViewAdapter extends ListAdapter<Trait, EditTraitsRecyclerViewAdapter.ViewHolder> {
|
||||
private static final DiffUtil.ItemCallback<Trait> DIFF_CALLBACK = new DiffUtil.ItemCallback<Trait>() {
|
||||
|
||||
public class EditTraitsRecyclerViewAdapter extends RecyclerView.Adapter<EditTraitsRecyclerViewAdapter.ViewHolder> {
|
||||
private final List<Trait> mValues;
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull @NotNull Trait oldItem, @NonNull @NotNull Trait newItem) {
|
||||
return oldItem.equals(newItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull @NotNull Trait oldItem, @NonNull @NotNull Trait newItem) {
|
||||
return oldItem.equals(newItem);
|
||||
}
|
||||
};
|
||||
private final ItemCallback mOnClick;
|
||||
|
||||
public EditTraitsRecyclerViewAdapter(List<Trait> items, ItemCallback onClick) {
|
||||
mValues = items;
|
||||
protected EditTraitsRecyclerViewAdapter(ItemCallback onClick) {
|
||||
super(DIFF_CALLBACK);
|
||||
mOnClick = onClick;
|
||||
}
|
||||
|
||||
@@ -30,8 +42,8 @@ public class EditTraitsRecyclerViewAdapter extends RecyclerView.Adapter<EditTrai
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
holder.mItem = mValues.get(position);
|
||||
holder.mContentView.setText(mValues.get(position).name);
|
||||
holder.mItem = getItem(position);
|
||||
holder.mContentView.setText(holder.mItem.name);
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (mOnClick != null) {
|
||||
mOnClick.onItemCallback(holder.mItem);
|
||||
@@ -39,11 +51,6 @@ public class EditTraitsRecyclerViewAdapter extends RecyclerView.Adapter<EditTrai
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public interface ItemCallback {
|
||||
void onItemCallback(Trait trait);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class LibraryFragment extends MCFragment {
|
||||
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
recyclerView.addItemDecoration(dividerItemDecoration);
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(requireContext(), adapter::deleteItem));
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(requireContext(), (position, direction) -> adapter.deleteItem(position), null));
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,14 @@ public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
||||
private final Drawable icon;
|
||||
private final ColorDrawable background;
|
||||
private final Paint clearPaint;
|
||||
private final OnDeleteCallback mOnDelete;
|
||||
private final OnSwipeCallback mOnDelete;
|
||||
private final OnMoveCallback mOnMove;
|
||||
private final Context mContext;
|
||||
public SwipeToDeleteCallback(Context context, OnDeleteCallback onDelete) {
|
||||
super(0, ItemTouchHelper.LEFT);
|
||||
|
||||
public SwipeToDeleteCallback(Context context, OnSwipeCallback onDelete, OnMoveCallback onMove) {
|
||||
super(onMove == null ? 0 : ItemTouchHelper.UP | ItemTouchHelper.DOWN, onDelete == null ? 0 : ItemTouchHelper.LEFT);
|
||||
mOnDelete = onDelete;
|
||||
mOnMove = onMove;
|
||||
mContext = context;
|
||||
icon = ContextCompat.getDrawable(mContext, R.drawable.ic_delete_white_36);
|
||||
background = new ColorDrawable(context.getResources().getColor(R.color.red));
|
||||
@@ -39,6 +42,11 @@ public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||
@NonNull RecyclerView.ViewHolder target
|
||||
) {
|
||||
if (mOnMove != null) {
|
||||
int from = viewHolder.getAdapterPosition();
|
||||
int to = target.getAdapterPosition();
|
||||
return mOnMove.onMove(from, to);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,7 +54,7 @@ public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
if (mOnDelete != null) {
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
mOnDelete.onDelete(position);
|
||||
mOnDelete.onSwipe(position, direction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +88,11 @@ public class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
}
|
||||
|
||||
public interface OnDeleteCallback {
|
||||
void onDelete(int position);
|
||||
public interface OnSwipeCallback {
|
||||
void onSwipe(int position, int direction);
|
||||
}
|
||||
|
||||
public interface OnMoveCallback {
|
||||
boolean onMove(int from, int to);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user