Adds edit skill fragment to edit individual skills.

This commit is contained in:
2021-06-20 00:51:56 -07:00
committed by Tom Hicks
parent 54f863ee5f
commit d214d615e5
4 changed files with 129 additions and 57 deletions

View File

@@ -9,6 +9,7 @@ import android.widget.EditText;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavBackStackEntry;
import androidx.navigation.NavController; import androidx.navigation.NavController;
@@ -19,25 +20,24 @@ import com.majinnaibu.monstercards.models.Skill;
import com.majinnaibu.monstercards.ui.components.AbilityScorePicker; import com.majinnaibu.monstercards.ui.components.AbilityScorePicker;
import com.majinnaibu.monstercards.ui.components.AdvantagePicker; import com.majinnaibu.monstercards.ui.components.AdvantagePicker;
import com.majinnaibu.monstercards.ui.components.ProficiencyPicker; 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.Logger;
import com.majinnaibu.monstercards.utils.TextChangedListener; import com.majinnaibu.monstercards.utils.TextChangedListener;
public class EditSkillFragment extends MCFragment { public class EditSkillFragment extends Fragment {
private EditMonsterViewModel mEditMonsterViewModel; private EditMonsterViewModel mEditMonsterViewModel;
private EditSkillViewModel mViewModel; private EditSkillViewModel mViewModel;
private ViewHolder mHolder; private ViewHolder mHolder;
private Skill mOldSkill; private Skill mOldSkill;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
mViewModel = new ViewModelProvider(this).get(EditSkillViewModel.class); mViewModel = new ViewModelProvider(this).get(EditSkillViewModel.class);
if (getArguments() != null) { if (getArguments() != null) {
EditSkillFragmentArgs args = EditSkillFragmentArgs.fromBundle(getArguments()); EditSkillFragmentArgs args = EditSkillFragmentArgs.fromBundle(getArguments());
mViewModel.copyFromSkill(args.getName(), args.getAbilityScore(), args.getProficiency(), args.getAdvantage());
mOldSkill = new Skill(args.getName(), args.getAbilityScore(), args.getAdvantage(), args.getProficiency()); mOldSkill = new Skill(args.getName(), args.getAbilityScore(), args.getAdvantage(), args.getProficiency());
mViewModel.copyFromSkill(mOldSkill);
} else { } else {
Logger.logWTF("EditSkillFragment needs arguments."); Logger.logWTF("This should never happen. EditSkillFragment needs arguments.");
mOldSkill = null; mOldSkill = null;
} }
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -49,7 +49,10 @@ public class EditSkillFragment extends MCFragment {
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment); NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation); NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
mEditMonsterViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class); mEditMonsterViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_edit_skill, container, false); View root = inflater.inflate(R.layout.fragment_edit_skill, container, false);
mHolder = new ViewHolder(root); mHolder = new ViewHolder(root);
mHolder.abilityScore.setValue(mViewModel.getAbilityScore().getValue()); mHolder.abilityScore.setValue(mViewModel.getAbilityScore().getValue());
@@ -77,19 +80,13 @@ public class EditSkillFragment extends MCFragment {
return root; return root;
} }
@Override
public void onStart() {
super.onStart();
mHolder.name.requestFocus();
}
private static class ViewHolder { private static class ViewHolder {
AbilityScorePicker abilityScore; AbilityScorePicker abilityScore;
AdvantagePicker advantage; AdvantagePicker advantage;
ProficiencyPicker proficiency; ProficiencyPicker proficiency;
EditText name; EditText name;
ViewHolder(@NonNull View root) { ViewHolder(View root) {
abilityScore = root.findViewById(R.id.abilityScore); abilityScore = root.findViewById(R.id.abilityScore);
advantage = root.findViewById(R.id.advantage); advantage = root.findViewById(R.id.advantage);
proficiency = root.findViewById(R.id.proficiency); proficiency = root.findViewById(R.id.proficiency);

View File

@@ -1,37 +1,57 @@
package com.majinnaibu.monstercards.ui.editmonster; package com.majinnaibu.monstercards.ui.editmonster;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData; 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.AbilityScore;
import com.majinnaibu.monstercards.data.enums.AdvantageType; import com.majinnaibu.monstercards.data.enums.AdvantageType;
import com.majinnaibu.monstercards.data.enums.ProficiencyType; import com.majinnaibu.monstercards.data.enums.ProficiencyType;
import com.majinnaibu.monstercards.models.Skill; import com.majinnaibu.monstercards.models.Skill;
import com.majinnaibu.monstercards.ui.shared.ChangeTrackedViewModel;
import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData; import com.majinnaibu.monstercards.utils.ChangeTrackedLiveData;
public class EditSkillViewModel extends ChangeTrackedViewModel { public class EditSkillViewModel extends ViewModel {
private final ChangeTrackedLiveData<AbilityScore> mAbilityScore; private final ChangeTrackedLiveData<AbilityScore> mAbilityScore;
private final ChangeTrackedLiveData<AdvantageType> mAdvantageType; private final ChangeTrackedLiveData<AdvantageType> mAdvantageType;
private final MutableLiveData<Boolean> mHasChanges;
private final ChangeTrackedLiveData<ProficiencyType> mProficiencyType; private final ChangeTrackedLiveData<ProficiencyType> mProficiencyType;
private final ChangeTrackedLiveData<String> mName; private final ChangeTrackedLiveData<String> mName;
private final ChangeTrackedLiveData<Skill> mSkill; private final ChangeTrackedLiveData<Skill> mSkill;
public EditSkillViewModel() { public EditSkillViewModel() {
super(); mHasChanges = new MutableLiveData<>(false);
mAbilityScore = new ChangeTrackedLiveData<>(AbilityScore.STRENGTH, this::makeDirty); ChangeTrackedLiveData.OnValueDirtiedCallback onDirtied = () -> mHasChanges.setValue(true);
mAdvantageType = new ChangeTrackedLiveData<>(AdvantageType.NONE, this::makeDirty);
mProficiencyType = new ChangeTrackedLiveData<>(ProficiencyType.NONE, this::makeDirty); mAbilityScore = new ChangeTrackedLiveData<>(AbilityScore.STRENGTH, onDirtied);
mName = new ChangeTrackedLiveData<>("New Skill", this::makeDirty); mAdvantageType = new ChangeTrackedLiveData<>(AdvantageType.NONE, onDirtied);
mSkill = new ChangeTrackedLiveData<>(makeSkill(), this::makeDirty); mProficiencyType = new ChangeTrackedLiveData<>(ProficiencyType.NONE, onDirtied);
mName = new ChangeTrackedLiveData<>("Unknown Skill", onDirtied);
mSkill = new ChangeTrackedLiveData<>(makeSkill(), onDirtied);
} }
public void copyFromSkill(@NonNull Skill skill) { 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);
}
public void copyFromSkill(Skill skill) {
mAbilityScore.resetValue(skill.abilityScore); mAbilityScore.resetValue(skill.abilityScore);
mAdvantageType.resetValue(skill.advantageType); mAdvantageType.resetValue(skill.advantageType);
mProficiencyType.resetValue(skill.proficiencyType); mProficiencyType.resetValue(skill.proficiencyType);
mName.resetValue(skill.name); mName.resetValue(skill.name);
makeClean(); }
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<Skill> getSkill() { public LiveData<Skill> getSkill() {
@@ -74,7 +94,14 @@ public class EditSkillViewModel extends ChangeTrackedViewModel {
mSkill.setValue(makeSkill()); mSkill.setValue(makeSkill());
} }
@NonNull public LiveData<Boolean> getHasChanges() {
return mHasChanges;
}
public boolean hasChanges() {
return mHasChanges.getValue();
}
private Skill makeSkill() { private Skill makeSkill() {
return new Skill(mName.getValue(), mAbilityScore.getValue(), mAdvantageType.getValue(), mProficiencyType.getValue()); return new Skill(mName.getValue(), mAbilityScore.getValue(), mAdvantageType.getValue(), mProficiencyType.getValue());
} }

View File

@@ -3,9 +3,6 @@ package com.majinnaibu.monstercards.ui.editmonster;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -14,57 +11,87 @@ import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavBackStackEntry;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.Navigation; import androidx.navigation.Navigation;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.R;
import com.majinnaibu.monstercards.models.Skill;
import com.majinnaibu.monstercards.ui.shared.SwipeToDeleteCallback;
import com.majinnaibu.monstercards.utils.Logger;
/** /**
* A fragment representing a list of Items. * A fragment representing a list of Items.
*/ */
@SuppressWarnings("FieldCanBeLocal")
public class EditSkillsFragment extends Fragment { public class EditSkillsFragment extends Fragment {
private EditMonsterViewModel mViewModel; private EditMonsterViewModel mViewModel;
// private ViewHolder mHolder; private ViewHolder mHolder;
private void navigateToEditSkill(Skill skill) {
NavDirections action = EditSkillsFragmentDirections.actionEditSkillsFragmentToEditSkillFragment(skill.name, skill.abilityScore, skill.proficiencyType, skill.advantageType);
View view = getView();
assert view != null;
Navigation.findNavController(view).navigate(action);
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_skills_list, container, false);
NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment); NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment);
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation); NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation);
mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class); mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class);
setHasOptionsMenu(true);
// Set the adapter View root = inflater.inflate(R.layout.fragment_edit_skills_list, container, false);
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
recyclerView.setLayoutManager(new LinearLayoutManager(context));
mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> recyclerView.setAdapter(new EditSkillsRecyclerViewAdapter(mViewModel.getSkillsArray())));
}
return view; mHolder = new ViewHolder(root);
setupRecyclerView(mHolder.list);
setupAddSkillButton(mHolder.addSkill);
return root;
} }
@Override private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { Context context = requireContext();
inflater.inflate(R.menu.edit_skills_menu, menu); LinearLayoutManager layoutManager = new LinearLayoutManager(context);
super.onCreateOptionsMenu(menu, inflater); recyclerView.setLayoutManager(layoutManager);
mViewModel.getSkills().observe(getViewLifecycleOwner(), skills -> {
EditSkillsRecyclerViewAdapter adapter = new EditSkillsRecyclerViewAdapter(mViewModel.getSkillsArray(), skill -> {
if (skill != null) {
navigateToEditSkill(skill);
} else {
Logger.logError("Can't navigate to EditSkill with a null skill");
}
}, null);
recyclerView.setAdapter(adapter);
});
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new SwipeToDeleteCallback(context, mViewModel::removeSkill));
itemTouchHelper.attachToRecyclerView(recyclerView);
} }
@Override private void setupAddSkillButton(@NonNull FloatingActionButton fab) {
public boolean onOptionsItemSelected(@NonNull MenuItem item) { fab.setOnClickListener(view -> {
if (item.getItemId() == R.id.menu_action_add_skill) { Skill newSkill = mViewModel.addNewSkill();
mViewModel.addNewSkill(); navigateToEditSkill(newSkill);
// TODO: navigate to editing the new skill });
// NavDirections action = MonsterDetailFragmentDirections.actionNavigationMonsterToEditMonsterFragment(monsterDetailViewModel.getId().getValue().toString()); }
// View view = getView();
// assert view != null; private static class ViewHolder {
// Navigation.findNavController(view).navigate(action); RecyclerView list;
return true; FloatingActionButton addSkill;
ViewHolder(View root) {
this.list = root.findViewById(R.id.list);
this.addSkill = root.findViewById(R.id.add_skill);
} }
return super.onOptionsItemSelected(item);
} }
} }

View File

@@ -127,7 +127,28 @@
android:id="@+id/editSkillsFragment" android:id="@+id/editSkillsFragment"
android:name="com.majinnaibu.monstercards.ui.editmonster.EditSkillsFragment" android:name="com.majinnaibu.monstercards.ui.editmonster.EditSkillsFragment"
android:label="fragment_edit_skills_list" android:label="fragment_edit_skills_list"
tools:layout="@layout/fragment_edit_skills_list" /> tools:layout="@layout/fragment_edit_skills_list">
<action
android:id="@+id/action_editSkillsFragment_to_editSkillFragment"
app:destination="@id/editSkillFragment" />
</fragment>
<fragment
android:id="@+id/editSkillFragment"
android:name="com.majinnaibu.monstercards.ui.editmonster.EditSkillFragment"
android:label="fragment_edit_skill"
tools:layout="@layout/fragment_edit_skill">
<argument
android:name="name"
app:argType="string" />
<argument
android:name="abilityScore"
app:argType="com.majinnaibu.monstercards.data.enums.AbilityScore" />
<argument
android:name="proficiency"
app:argType="com.majinnaibu.monstercards.data.enums.ProficiencyType" />
<argument
android:name="advantage"
app:argType="com.majinnaibu.monstercards.data.enums.AdvantageType" />
</fragment>
</navigation> </navigation>
</navigation> </navigation>