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 b7a0885..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 @@ -4,17 +4,31 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +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; +import androidx.navigation.NavDirections; +import androidx.navigation.Navigation; 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.utils.Logger; -public class EditMonsterFragment extends Fragment { +import java.util.UUID; + +import io.reactivex.rxjava3.observers.DisposableSingleObserver; + +public class EditMonsterFragment extends MCFragment { private EditMonsterViewModel mViewModel; + private ViewHolder mHolder; public static EditMonsterFragment newInstance() { return new EditMonsterFragment(); @@ -23,14 +37,68 @@ public class EditMonsterFragment extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_edit_monster, container, false); + + MonsterRepository repository = getMonsterRepository(); + Bundle arguments = getArguments(); + 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. + 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; } @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 { + + TextView basicInfoButton; + + ViewHolder(View root) { + basicInfoButton = root.findViewById(R.id.basicInfo); + } + } } \ No newline at end of file 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 08d3cc6..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 @@ -1,7 +1,133 @@ 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.models.Monster; + +import java.util.UUID; + public class EditMonsterViewModel extends ViewModel { - // TODO: Implement the ViewModel -} \ No newline at end of file + 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<>(""); + 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() { + return mName; + } + + public void setName(@NonNull String name) { + 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 419b928..e05ebba 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -34,4 +34,14 @@ Legendary Actions Lair Actions Regional Actions + Edit %1$s + Unnamed Monster + Failed to create monster + %1$s created + Name + Size + Type + Subtype + Alignment + Custom HP \ No newline at end of file