From 43dcbf33adc72e935c518c3a7a0e621fe5694b69 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 7 Aug 2021 16:08:07 +0200 Subject: [PATCH] Android: Add edit button for cheats --- .../features/cheats/model/ARCheat.java | 5 + .../features/cheats/model/AbstractCheat.java | 16 +++ .../features/cheats/model/Cheat.java | 10 ++ .../cheats/model/CheatsViewModel.java | 14 +++ .../features/cheats/model/GeckoCheat.java | 5 + .../features/cheats/model/PatchCheat.java | 5 + .../cheats/ui/CheatDetailsFragment.java | 64 ++++++++++- .../res/layout/fragment_cheat_details.xml | 100 ++++++++++++++---- .../app/src/main/res/values/strings.xml | 2 + Source/Android/jni/CMakeLists.txt | 1 + Source/Android/jni/Cheats/ARCheat.cpp | 17 +++ Source/Android/jni/Cheats/Cheats.h | 7 ++ Source/Android/jni/Cheats/GeckoCheat.cpp | 17 +++ Source/Android/jni/Cheats/PatchCheat.cpp | 17 +++ 14 files changed, 253 insertions(+), 27 deletions(-) create mode 100644 Source/Android/jni/Cheats/Cheats.h diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/ARCheat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/ARCheat.java index ebb4ee9416..bed39c2dbd 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/ARCheat.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/ARCheat.java @@ -22,8 +22,13 @@ public class ARCheat extends AbstractCheat @NonNull public native String getName(); + public native boolean getUserDefined(); + public native boolean getEnabled(); + @Override + protected native int trySetImpl(@NonNull String name); + @Override protected native void setEnabledImpl(boolean enabled); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/AbstractCheat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/AbstractCheat.java index 8f6121808a..60391895c7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/AbstractCheat.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/AbstractCheat.java @@ -2,12 +2,26 @@ package org.dolphinemu.dolphinemu.features.cheats.model; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; public abstract class AbstractCheat implements Cheat { private Runnable mChangedCallback = null; + public int trySet(@NonNull String name) + { + if (name.isEmpty()) + return TRY_SET_FAIL_NO_NAME; + + int result = trySetImpl(name); + + if (result == TRY_SET_SUCCESS) + onChanged(); + + return result; + } + public void setEnabled(boolean enabled) { setEnabledImpl(enabled); @@ -25,5 +39,7 @@ public abstract class AbstractCheat implements Cheat mChangedCallback.run(); } + protected abstract int trySetImpl(@NonNull String name); + protected abstract void setEnabledImpl(boolean enabled); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/Cheat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/Cheat.java index 97bd57d885..baf8ebb5be 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/Cheat.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/Cheat.java @@ -3,13 +3,23 @@ package org.dolphinemu.dolphinemu.features.cheats.model; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public interface Cheat { + int TRY_SET_FAIL_NO_NAME = -1; + int TRY_SET_SUCCESS = 0; + @NonNull String getName(); + int trySet(@NonNull String name); + + boolean getUserDefined(); + boolean getEnabled(); void setEnabled(boolean enabled); + + void setChangedCallback(@Nullable Runnable callback); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/CheatsViewModel.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/CheatsViewModel.java index aac6c02ed0..e4e5298104 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/CheatsViewModel.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/CheatsViewModel.java @@ -11,6 +11,7 @@ public class CheatsViewModel extends ViewModel private boolean mLoaded = false; private final MutableLiveData mSelectedCheat = new MutableLiveData<>(null); + private final MutableLiveData mIsEditing = new MutableLiveData<>(false); private final MutableLiveData mOpenDetailsViewEvent = new MutableLiveData<>(false); @@ -75,9 +76,22 @@ public class CheatsViewModel extends ViewModel public void setSelectedCheat(Cheat cheat) { + if (mIsEditing.getValue()) + setIsEditing(false); + mSelectedCheat.setValue(cheat); } + public LiveData getIsEditing() + { + return mIsEditing; + } + + public void setIsEditing(boolean isEditing) + { + mIsEditing.setValue(isEditing); + } + public LiveData getOpenDetailsViewEvent() { return mOpenDetailsViewEvent; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/GeckoCheat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/GeckoCheat.java index f6ea493ac3..06815d1fe9 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/GeckoCheat.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/GeckoCheat.java @@ -22,8 +22,13 @@ public class GeckoCheat extends AbstractCheat @NonNull public native String getName(); + public native boolean getUserDefined(); + public native boolean getEnabled(); + @Override + protected native int trySetImpl(@NonNull String name); + @Override protected native void setEnabledImpl(boolean enabled); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/PatchCheat.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/PatchCheat.java index 411df3cdc0..b4e0ee3e53 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/PatchCheat.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/model/PatchCheat.java @@ -22,8 +22,13 @@ public class PatchCheat extends AbstractCheat @NonNull public native String getName(); + public native boolean getUserDefined(); + public native boolean getEnabled(); + @Override + protected native int trySetImpl(@NonNull String name); + @Override protected native void setEnabledImpl(boolean enabled); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java index 90356b63eb..0b7ce49785 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.EditText; import androidx.annotation.NonNull; @@ -22,6 +23,9 @@ public class CheatDetailsFragment extends Fragment { private View mRoot; private EditText mEditName; + private Button mButtonEdit; + private Button mButtonCancel; + private Button mButtonOk; private CheatsViewModel mViewModel; private Cheat mCheat; @@ -39,24 +43,74 @@ public class CheatDetailsFragment extends Fragment { mRoot = view.findViewById(R.id.root); mEditName = view.findViewById(R.id.edit_name); + mButtonEdit = view.findViewById(R.id.button_edit); + mButtonCancel = view.findViewById(R.id.button_cancel); + mButtonOk = view.findViewById(R.id.button_ok); CheatsActivity activity = (CheatsActivity) requireActivity(); mViewModel = new ViewModelProvider(activity).get(CheatsViewModel.class); - LiveData selectedCheat = mViewModel.getSelectedCheat(); - selectedCheat.observe(getViewLifecycleOwner(), this::populateFields); - populateFields(selectedCheat.getValue()); + mViewModel.getSelectedCheat().observe(getViewLifecycleOwner(), this::onSelectedCheatUpdated); + mViewModel.getIsEditing().observe(getViewLifecycleOwner(), this::onIsEditingUpdated); + + mButtonEdit.setOnClickListener((v) -> mViewModel.setIsEditing(true)); + mButtonCancel.setOnClickListener((v) -> + { + mViewModel.setIsEditing(false); + onSelectedCheatUpdated(mCheat); + }); + mButtonOk.setOnClickListener(this::onOkClicked); } - private void populateFields(@Nullable Cheat cheat) + private void clearEditErrors() { + mEditName.setError(null); + } + + private void onOkClicked(View view) + { + clearEditErrors(); + + int result = mCheat.trySet(mEditName.getText().toString()); + + switch (result) + { + case Cheat.TRY_SET_SUCCESS: + mViewModel.setIsEditing(false); + break; + case Cheat.TRY_SET_FAIL_NO_NAME: + mEditName.setError(getText(R.string.cheats_error_no_name)); + break; + } + } + + private void onSelectedCheatUpdated(@Nullable Cheat cheat) + { + clearEditErrors(); + mRoot.setVisibility(cheat == null ? View.GONE : View.VISIBLE); - if (cheat != null && cheat != mCheat) + boolean userDefined = cheat != null && cheat.getUserDefined(); + mButtonEdit.setEnabled(userDefined); + + // If the fragment was recreated while editing a cheat, it's vital that we + // don't repopulate the fields, otherwise the user's changes will be lost + boolean isEditing = mViewModel.getIsEditing().getValue(); + + if (!isEditing && cheat != null) { mEditName.setText(cheat.getName()); } mCheat = cheat; } + + private void onIsEditingUpdated(boolean isEditing) + { + mEditName.setEnabled(isEditing); + + mButtonEdit.setVisibility(isEditing ? View.GONE : View.VISIBLE); + mButtonCancel.setVisibility(isEditing ? View.VISIBLE : View.GONE); + mButtonOk.setVisibility(isEditing ? View.VISIBLE : View.GONE); + } } diff --git a/Source/Android/app/src/main/res/layout/fragment_cheat_details.xml b/Source/Android/app/src/main/res/layout/fragment_cheat_details.xml index 14c7dfeace..4afb27f344 100644 --- a/Source/Android/app/src/main/res/layout/fragment_cheat_details.xml +++ b/Source/Android/app/src/main/res/layout/fragment_cheat_details.xml @@ -5,35 +5,91 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/root" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="match_parent"> - + app:layout_constraintBottom_toTopOf="@id/barrier"> - + + + + + + + + + + + +