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 3fba542..10a4377 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 @@ -6,60 +6,70 @@ import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.navigation.NavBackStackEntry; import androidx.navigation.NavController; import androidx.navigation.Navigation; -import com.google.android.material.switchmaterial.SwitchMaterial; import com.majinnaibu.monstercards.R; -import com.majinnaibu.monstercards.ui.components.Stepper; -import com.majinnaibu.monstercards.ui.shared.MCFragment; +import com.majinnaibu.monstercards.ui.MCFragment; +import com.majinnaibu.monstercards.utils.Logger; import com.majinnaibu.monstercards.utils.TextChangedListener; +/** + * A simple {@link Fragment} subclass. + */ public class EditBasicInfoFragment extends MCFragment { private EditMonsterViewModel mViewModel; private ViewHolder mHolder; @Override - public void onStart() { - super.onStart(); - mHolder.name.requestFocus(); - } - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + 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_basic_info, container, false); - mHolder = new ViewHolder(root); + // Inflate the layout for this fragment + View root = inflater.inflate(R.layout.fragment_edit_basic_info, container, false); + + mHolder = new ViewHolder(root); mHolder.name.setText(mViewModel.getName().getValue()); - mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setName(s.toString()))); + mHolder.name.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setName(s.toString()); + Logger.logDebug(String.format("Monster Name changed to %s", mViewModel.getName().getValue())); + })); mHolder.size.setText(mViewModel.getSize().getValue()); - mHolder.size.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setSize(s.toString()))); + mHolder.size.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setSize(s.toString()); + Logger.logDebug(String.format("Monster Size changed to %s", mViewModel.getSize().getValue())); + })); mHolder.type.setText(mViewModel.getType().getValue()); - mHolder.type.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setType(s.toString()))); + mHolder.type.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setType(s.toString()); + Logger.logDebug(String.format("Monster Type changed to %s", mViewModel.getType().getValue())); + })); mHolder.subtype.setText(mViewModel.getSubtype().getValue()); - mHolder.subtype.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setSubtype(s.toString()))); + mHolder.subtype.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setSubtype(s.toString()); + Logger.logDebug(String.format("Monster Subtype changed to %s", mViewModel.getSubtype().getValue())); + })); mHolder.alignment.setText(mViewModel.getAlignment().getValue()); - mHolder.alignment.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setAlignment(s.toString()))); + mHolder.alignment.addTextChangedListener(new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setAlignment(s.toString()); + Logger.logDebug(String.format("Monster Alignment changed to %s", mViewModel.getAlignment().getValue())); + })); mHolder.customHitPoints.setText(mViewModel.getCustomHitPoints().getValue()); - mHolder.customHitPoints.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> mViewModel.setCustomHitPoints(s.toString())))); - - mHolder.hitDice.setValue(mViewModel.getHitDiceUnboxed()); - mHolder.hitDice.setOnValueChangeListener((newValue, oldValue) -> mViewModel.setHitDice(newValue)); - - mHolder.hasCustomHitPoints.setChecked(mViewModel.getHasCustomHitPointsValueAsBoolean()); - mHolder.hasCustomHitPoints.setOnCheckedChangeListener((button, isChecked) -> mViewModel.setHasCustomHitPoints(isChecked)); + mHolder.customHitPoints.addTextChangedListener((new TextChangedListener((TextChangedListener.OnTextChangedCallback) (s, start, before, count) -> { + mViewModel.setCustomHitPoints(s.toString()); + Logger.logDebug(String.format("Monster Custom Hit Points changed to %s", mViewModel.getCustomHitPoints().getValue())); + }))); return root; } @@ -71,18 +81,15 @@ public class EditBasicInfoFragment extends MCFragment { private final EditText subtype; private final EditText alignment; private final EditText customHitPoints; - private final Stepper hitDice; - private final SwitchMaterial hasCustomHitPoints; - ViewHolder(@NonNull View root) { + ViewHolder(View root) { name = root.findViewById(R.id.name); size = root.findViewById(R.id.size); type = root.findViewById(R.id.type); subtype = root.findViewById(R.id.subtype); alignment = root.findViewById(R.id.alignment); customHitPoints = root.findViewById(R.id.customHitPoints); - hitDice = root.findViewById(R.id.hitDice); - hasCustomHitPoints = root.findViewById(R.id.hasCustomHitPoints); + // TODO: add hitDice, hasCustomHitPoints, and customHitPoints } } -} +} \ 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 e0d03a1..af63ae3 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 @@ -9,6 +9,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; +import androidx.navigation.NavBackStackEntry; +import androidx.navigation.NavController; +import androidx.navigation.NavDirections; +import androidx.navigation.Navigation; import com.majinnaibu.monstercards.R; import com.majinnaibu.monstercards.data.MonsterRepository; @@ -39,33 +43,46 @@ public class EditMonsterFragment extends MCFragment { assert arguments != null; UUID monsterId = UUID.fromString(MonsterDetailFragmentArgs.fromBundle(arguments).getMonsterId()); + NavController navController = Navigation.findNavController(requireActivity(), R.id.nav_host_fragment); + NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.edit_monster_navigation); + mViewModel = new ViewModelProvider(backStackEntry).get(EditMonsterViewModel.class); + View root = inflater.inflate(R.layout.fragment_edit_monster, container, false); mHolder = new ViewHolder(root); requireAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.title_edit_monster, getString(R.string.default_monster_name))); // TODO: Show a loading spinner until we have the monster loaded. - repository.getMonster(monsterId).toObservable() - .firstOrError() - .subscribe(new DisposableSingleObserver() { - @Override - public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) { - Logger.logDebug(String.format("Monster loaded: %s", monster.name)); - mViewModel.copyFromMonster(monster); - requireAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.title_edit_monster, monster.name)); - dispose(); - } - - @Override - public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { - // TODO: Show an error state. - Logger.logError(e); - dispose(); - } - }); + if (mViewModel.hasError() || !mViewModel.hasLoaded() || !mViewModel.getMonsterId().getValue().equals(monsterId)) { + repository.getMonster(monsterId).toObservable() + .firstOrError() + .subscribe(new DisposableSingleObserver() { + @Override + public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull Monster monster) { + Logger.logDebug(String.format("Monster loaded: %s", monster.name)); + mViewModel.setHasLoaded(true); + mViewModel.setHasError(false); + mViewModel.copyFromMonster(monster); + requireAppCompatActivity().getSupportActionBar().setTitle(getString(R.string.title_edit_monster, monster.name)); + dispose(); + } + @Override + public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) { + // TODO: Show an error state. + Logger.logError(e); + mViewModel.setHasError(true); + mViewModel.setErrorMessage(e.toString()); + dispose(); + } + }); + } mHolder.basicInfoButton.setOnClickListener(v -> { // TODO: Navigate to the EditBasicInfo fragment Logger.logDebug("Basic Info clicked"); + NavDirections action = EditMonsterFragmentDirections.actionEditMonsterFragmentToEditBasicInfoFragment(); + View view = getView(); + assert view != null; + Navigation.findNavController(view).navigate(action); }); return root; @@ -74,8 +91,6 @@ public class EditMonsterFragment extends MCFragment { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - mViewModel = new ViewModelProvider(this).get(EditMonsterViewModel.class); - // TODO: Use the ViewModel } private static class ViewHolder { 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 a5c6aaa..a953409 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 @@ -10,22 +10,40 @@ import com.majinnaibu.monstercards.models.Monster; import java.util.UUID; public class EditMonsterViewModel extends ViewModel { - private MutableLiveData mName; - private MutableLiveData mMonsterId; + private final MutableLiveData mName; + private final MutableLiveData mMonsterId; + private final MutableLiveData mErrorMessage; + private final MutableLiveData mHasError; + private final MutableLiveData mHasLoaded; + private final MutableLiveData mSize; + private final MutableLiveData mType; + private final MutableLiveData mSubtype; + private final MutableLiveData mAlignment; + private final MutableLiveData mCustomHitPoints; public EditMonsterViewModel() { - mName = new MutableLiveData<>(); - mName.setValue(""); - - mMonsterId = new MutableLiveData<>(); - mMonsterId.setValue(UUID.randomUUID()); + mName = new MutableLiveData<>(""); + mMonsterId = new MutableLiveData<>(UUID.randomUUID()); + mErrorMessage = new MutableLiveData<>(""); + mHasError = new MutableLiveData<>(false); + mHasLoaded = new MutableLiveData<>(false); + mSize = new MutableLiveData<>(""); + mType = new MutableLiveData<>(""); + mSubtype = new MutableLiveData<>(""); + mAlignment = new MutableLiveData<>(""); + mCustomHitPoints = new MutableLiveData<>(""); } public void copyFromMonster(Monster monster) { // TODO: copy from monster to other fields mMonsterId.setValue(monster.id); mName.setValue(monster.name); + mSize.setValue(monster.size); + mType.setValue(monster.type); + mSubtype.setValue(monster.subtype); + mAlignment.setValue(monster.alignment); + mCustomHitPoints.setValue(monster.customHPDescription); } public LiveData getName() { @@ -36,4 +54,80 @@ public class EditMonsterViewModel extends ViewModel { mName.setValue(name); } + + public LiveData getMonsterId() { + return mMonsterId; + } + + public LiveData getErrorMessage() { + return mErrorMessage; + } + + public void setErrorMessage(@NonNull String errorMessage) { + mErrorMessage.setValue(errorMessage); + } + + public LiveData getHasError() { + return mHasError; + } + + public void setHasError(@NonNull Boolean hasError) { + mHasError.setValue(hasError); + } + + public boolean hasError() { + return getHasError().getValue(); + } + + public LiveData getHasLoaded() { + return mHasLoaded; + } + + public void setHasLoaded(@NonNull Boolean hasLoaded) { + mHasLoaded.setValue(hasLoaded); + } + + public boolean hasLoaded() { + return getHasLoaded().getValue(); + } + + public LiveData getSize() { + return mSize; + } + + public void setSize(@NonNull String size) { + mSize.setValue(size); + } + + public LiveData getType() { + return mType; + } + + public void setType(@NonNull String type) { + mType.setValue(type); + } + + public LiveData getSubtype() { + return mSubtype; + } + + public void setSubtype(@NonNull String subType) { + mSubtype.setValue(subType); + } + + public LiveData getAlignment() { + return mAlignment; + } + + public void setAlignment(@NonNull String alignment) { + mAlignment.setValue(alignment); + } + + public LiveData getCustomHitPoints() { + return mCustomHitPoints; + } + + public void setCustomHitPoints(String customHitPoints) { + mCustomHitPoints.setValue(customHitPoints); + } } diff --git a/Android/app/src/main/res/layout/fragment_edit_basic_info.xml b/Android/app/src/main/res/layout/fragment_edit_basic_info.xml index 1010c3e..865ce01 100644 --- a/Android/app/src/main/res/layout/fragment_edit_basic_info.xml +++ b/Android/app/src/main/res/layout/fragment_edit_basic_info.xml @@ -1,6 +1,5 @@ - - + diff --git a/Android/app/src/main/res/navigation/mobile_navigation.xml b/Android/app/src/main/res/navigation/mobile_navigation.xml index e2d33bc..e8eee2d 100644 --- a/Android/app/src/main/res/navigation/mobile_navigation.xml +++ b/Android/app/src/main/res/navigation/mobile_navigation.xml @@ -55,16 +55,32 @@ app:argType="string" /> + app:destination="@id/edit_monster_navigation" /> - + - + + + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/values/dimens.xml b/Android/app/src/main/res/values/dimens.xml index 97467f9..c6c3b92 100644 --- a/Android/app/src/main/res/values/dimens.xml +++ b/Android/app/src/main/res/values/dimens.xml @@ -2,5 +2,6 @@ 16dp 16dp + 20sp \ No newline at end of file diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index 4a28ae5..e05ebba 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -38,4 +38,10 @@ Unnamed Monster Failed to create monster %1$s created + Name + Size + Type + Subtype + Alignment + Custom HP \ No newline at end of file