summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2021-08-11 14:49:20 +0200
committerJosJuice <josjuice@gmail.com>2021-09-16 18:48:39 +0200
commit47efd3317d2cc6e317121a9ca10fb25808f85981 (patch)
tree0c3884e8e5ccb45878d270fdcedf423698e167e1 /Source/Android/app/src/main/java
parent215492152c6b5a20c600e727afcbef9ceace666a (diff)
Android: Fix CheatsActivity d-pad navigation
Special shoutout to Android for not having RTL compatible variants of nextFocusRight and nextFocusLeft. Ideally we would have some way to block the user from using the d-pad to switch between the two panes when in portrait mode, or make the list pane act as if it's to the left of the details pane rather than the right when the details pane is open, but I don't know of a good way to do this. SlidingPaneLayout doesn't really seem to have been implemented with d-pad navigation in mind. Thankfully, landscape is the most important use case for gamepads.
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatDetailsFragment.java25
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java2
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatWarningFragment.java4
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java76
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java19
5 files changed, 115 insertions, 11 deletions
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 421b0aa094..2ab6bb31b0 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
@@ -73,13 +73,12 @@ public class CheatDetailsFragment extends Fragment
mViewModel.getIsEditing().observe(getViewLifecycleOwner(), this::onIsEditingUpdated);
mButtonDelete.setOnClickListener(this::onDeleteClicked);
- mButtonEdit.setOnClickListener((v) -> mViewModel.setIsEditing(true));
- mButtonCancel.setOnClickListener((v) ->
- {
- mViewModel.setIsEditing(false);
- onSelectedCheatUpdated(mCheat);
- });
+ mButtonEdit.setOnClickListener(this::onEditClicked);
+ mButtonCancel.setOnClickListener(this::onCancelClicked);
mButtonOk.setOnClickListener(this::onOkClicked);
+
+ CheatsActivity.setOnFocusChangeListenerRecursively(view,
+ (v, hasFocus) -> activity.onDetailsViewFocusChange(hasFocus));
}
private void clearEditErrors()
@@ -98,6 +97,19 @@ public class CheatDetailsFragment extends Fragment
builder.show();
}
+ private void onEditClicked(View view)
+ {
+ mViewModel.setIsEditing(true);
+ mButtonOk.requestFocus();
+ }
+
+ private void onCancelClicked(View view)
+ {
+ mViewModel.setIsEditing(false);
+ onSelectedCheatUpdated(mCheat);
+ mButtonDelete.requestFocus();
+ }
+
private void onOkClicked(View view)
{
clearEditErrors();
@@ -118,6 +130,7 @@ public class CheatDetailsFragment extends Fragment
mViewModel.notifySelectedCheatChanged();
mViewModel.setIsEditing(false);
}
+ mButtonEdit.requestFocus();
break;
case Cheat.TRY_SET_FAIL_NO_NAME:
mEditName.setError(getString(R.string.cheats_error_no_name));
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java
index 03f87f0c0c..efc446d50e 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatListFragment.java
@@ -36,7 +36,7 @@ public class CheatListFragment extends Fragment
CheatsActivity activity = (CheatsActivity) requireActivity();
CheatsViewModel viewModel = new ViewModelProvider(activity).get(CheatsViewModel.class);
- recyclerView.setAdapter(new CheatsAdapter(getViewLifecycleOwner(), viewModel));
+ recyclerView.setAdapter(new CheatsAdapter(activity, viewModel));
recyclerView.setLayoutManager(new LinearLayoutManager(activity));
recyclerView.addItemDecoration(new DividerItemDecoration(activity, null));
}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatWarningFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatWarningFragment.java
index aba0bb1602..df6d9d94b0 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatWarningFragment.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatWarningFragment.java
@@ -37,6 +37,10 @@ public class CheatWarningFragment extends Fragment implements View.OnClickListen
Button settingsButton = view.findViewById(R.id.button_settings);
settingsButton.setOnClickListener(this);
+
+ CheatsActivity activity = (CheatsActivity) requireActivity();
+ CheatsActivity.setOnFocusChangeListenerRecursively(view,
+ (v, hasFocus) -> activity.onListViewFocusChange(hasFocus));
}
@Override
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java
index 4143457006..42300e2b8d 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsActivity.java
@@ -5,8 +5,12 @@ package org.dolphinemu.dolphinemu.features.cheats.ui;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.view.ViewCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.slidingpanelayout.widget.SlidingPaneLayout;
@@ -18,6 +22,7 @@ import org.dolphinemu.dolphinemu.ui.TwoPaneOnBackPressedCallback;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
public class CheatsActivity extends AppCompatActivity
+ implements SlidingPaneLayout.PanelSlideListener
{
private static final String ARG_GAME_ID = "game_id";
private static final String ARG_REVISION = "revision";
@@ -29,6 +34,11 @@ public class CheatsActivity extends AppCompatActivity
private CheatsViewModel mViewModel;
private SlidingPaneLayout mSlidingPaneLayout;
+ private View mCheatList;
+ private View mCheatDetails;
+
+ private View mCheatListLastFocus;
+ private View mCheatDetailsLastFocus;
public static void launch(Context context, String gameId, int revision, boolean isWii)
{
@@ -59,6 +69,13 @@ public class CheatsActivity extends AppCompatActivity
setContentView(R.layout.activity_cheats);
mSlidingPaneLayout = findViewById(R.id.sliding_pane_layout);
+ mCheatList = findViewById(R.id.cheat_list);
+ mCheatDetails = findViewById(R.id.cheat_details);
+
+ mCheatListLastFocus = mCheatList;
+ mCheatDetailsLastFocus = mCheatDetails;
+
+ mSlidingPaneLayout.addPanelSlideListener(this);
getOnBackPressedDispatcher().addCallback(this,
new TwoPaneOnBackPressedCallback(mSlidingPaneLayout));
@@ -77,6 +94,25 @@ public class CheatsActivity extends AppCompatActivity
mViewModel.saveIfNeeded(mGameId, mRevision);
}
+ @Override
+ public void onPanelSlide(@NonNull View panel, float slideOffset)
+ {
+ }
+
+ @Override
+ public void onPanelOpened(@NonNull View panel)
+ {
+ boolean rtl = ViewCompat.getLayoutDirection(panel) == ViewCompat.LAYOUT_DIRECTION_RTL;
+ mCheatDetailsLastFocus.requestFocus(rtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT);
+ }
+
+ @Override
+ public void onPanelClosed(@NonNull View panel)
+ {
+ boolean rtl = ViewCompat.getLayoutDirection(panel) == ViewCompat.LAYOUT_DIRECTION_RTL;
+ mCheatListLastFocus.requestFocus(rtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT);
+ }
+
private void onSelectedCheatChanged(Cheat selectedCheat)
{
boolean cheatSelected = selectedCheat != null;
@@ -88,6 +124,30 @@ public class CheatsActivity extends AppCompatActivity
SlidingPaneLayout.LOCK_MODE_UNLOCKED : SlidingPaneLayout.LOCK_MODE_LOCKED_CLOSED);
}
+ public void onListViewFocusChange(boolean hasFocus)
+ {
+ if (hasFocus)
+ {
+ mCheatListLastFocus = mCheatList.findFocus();
+ if (mCheatListLastFocus == null)
+ throw new NullPointerException();
+
+ mSlidingPaneLayout.close();
+ }
+ }
+
+ public void onDetailsViewFocusChange(boolean hasFocus)
+ {
+ if (hasFocus)
+ {
+ mCheatDetailsLastFocus = mCheatDetails.findFocus();
+ if (mCheatDetailsLastFocus == null)
+ throw new NullPointerException();
+
+ mSlidingPaneLayout.open();
+ }
+ }
+
private void openDetailsView(boolean open)
{
if (open)
@@ -100,4 +160,20 @@ public class CheatsActivity extends AppCompatActivity
settings.loadSettings(null, mGameId, mRevision, mIsWii);
return settings;
}
+
+ public static void setOnFocusChangeListenerRecursively(@NonNull View view,
+ View.OnFocusChangeListener listener)
+ {
+ view.setOnFocusChangeListener(listener);
+
+ if (view instanceof ViewGroup)
+ {
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++)
+ {
+ View child = viewGroup.getChildAt(i);
+ setOnFocusChangeListenerRecursively(child, listener);
+ }
+ }
+ }
}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java
index c12cd58c9f..ed230f0513 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/cheats/ui/CheatsAdapter.java
@@ -20,25 +20,27 @@ import java.util.ArrayList;
public class CheatsAdapter extends RecyclerView.Adapter<CheatItemViewHolder>
{
+ private final CheatsActivity mActivity;
private final CheatsViewModel mViewModel;
- public CheatsAdapter(LifecycleOwner owner, CheatsViewModel viewModel)
+ public CheatsAdapter(CheatsActivity activity, CheatsViewModel viewModel)
{
+ mActivity = activity;
mViewModel = viewModel;
- mViewModel.getCheatAddedEvent().observe(owner, (position) ->
+ mViewModel.getCheatAddedEvent().observe(activity, (position) ->
{
if (position != null)
notifyItemInserted(position);
});
- mViewModel.getCheatChangedEvent().observe(owner, (position) ->
+ mViewModel.getCheatChangedEvent().observe(activity, (position) ->
{
if (position != null)
notifyItemChanged(position);
});
- mViewModel.getCheatDeletedEvent().observe(owner, (position) ->
+ mViewModel.getCheatDeletedEvent().observe(activity, (position) ->
{
if (position != null)
notifyItemRemoved(position);
@@ -55,12 +57,15 @@ public class CheatsAdapter extends RecyclerView.Adapter<CheatItemViewHolder>
{
case CheatItem.TYPE_CHEAT:
View cheatView = inflater.inflate(R.layout.list_item_cheat, parent, false);
+ addViewListeners(cheatView);
return new CheatViewHolder(cheatView);
case CheatItem.TYPE_HEADER:
View headerView = inflater.inflate(R.layout.list_item_header, parent, false);
+ addViewListeners(headerView);
return new HeaderViewHolder(headerView);
case CheatItem.TYPE_ACTION:
View actionView = inflater.inflate(R.layout.list_item_submenu, parent, false);
+ addViewListeners(actionView);
return new ActionViewHolder(actionView);
default:
throw new UnsupportedOperationException();
@@ -86,6 +91,12 @@ public class CheatsAdapter extends RecyclerView.Adapter<CheatItemViewHolder>
return getItemAt(position).getType();
}
+ private void addViewListeners(View view)
+ {
+ CheatsActivity.setOnFocusChangeListenerRecursively(view,
+ (v, hasFocus) -> mActivity.onListViewFocusChange(hasFocus));
+ }
+
private CheatItem getItemAt(int position)
{
// Patches