added sort game options

This commit is contained in:
izzy2lost
2025-09-01 15:36:45 -04:00
parent 5807d6cce6
commit a5e5b934e1
19 changed files with 787 additions and 516 deletions
@@ -112,11 +112,21 @@ public class CoversAdapter extends RecyclerView.Adapter<CoversAdapter.VH> {
}
}
holder.itemView.setOnClickListener(v -> {
if (onItemClick != null) onItemClick.onClick(real);
if (onItemClick != null) {
int pos = holder.getBindingAdapterPosition();
if (pos == RecyclerView.NO_POSITION) pos = position; // fallback
int count2 = titles.length;
int realNow = (count2 == 0) ? 0 : (pos % count2);
onItemClick.onClick(realNow);
}
});
holder.itemView.setOnLongClickListener(v -> {
if (onItemLongClick != null) {
onItemLongClick.onLongClick(real);
int pos = holder.getBindingAdapterPosition();
if (pos == RecyclerView.NO_POSITION) pos = position; // fallback
int count2 = titles.length;
int realNow = (count2 == 0) ? 0 : (pos % count2);
onItemLongClick.onLongClick(realNow);
return true;
}
return false;
@@ -14,6 +14,9 @@ import android.widget.Toast;
import android.os.Build;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -24,6 +27,9 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.PagerSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Locale;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class GamesCoverDialogFragment extends DialogFragment {
private boolean didInitialNudge = false;
@@ -37,11 +43,34 @@ public class GamesCoverDialogFragment extends DialogFragment {
private String[] uris;
private String[] coverUrls;
private String[] localPaths;
private String[] origTitles;
private String[] origUris;
private String[] origCoverUrls;
private String[] origLocalPaths;
private RecyclerView rv;
private LinearLayoutManager llm;
private PagerSnapHelper snapHelper;
private int lastRvW = -1, lastRvH = -1;
private boolean pendingResnap = false;
private int lastItemWidthPx = 0;
private RecyclerView rvLetters;
private LinearLayoutManager llmLetters;
private PagerSnapHelper lettersSnapHelper;
private LettersAdapter lettersAdapter;
private java.util.ArrayList<Character> letters = new java.util.ArrayList<>();
private Character pendingLetterJump = null;
private static final int SORT_ALPHA = 0;
private static final int SORT_RECENT = 1;
private int sortMode = SORT_ALPHA;
private String query = null;
// Simpler grouping/sort helpers (revert)
private static char firstLetter(String t) {
if (t == null) return '#';
String s = t.trim();
if (s.isEmpty()) return '#';
char c = Character.toUpperCase(s.charAt(0));
return Character.isLetter(c) ? c : '#';
}
public interface OnGameSelectedListener {
void onGameSelected(String gameUri);
@@ -98,6 +127,55 @@ public class GamesCoverDialogFragment extends DialogFragment {
// Snap to center item
snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(rv);
// Letters row setup
rvLetters = root.findViewById(R.id.recycler_letters);
if (rvLetters != null) {
rvLetters.setHasFixedSize(true);
llmLetters = new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false);
rvLetters.setLayoutManager(llmLetters);
rvLetters.setClipToPadding(false);
int basePad = (int)(24*getResources().getDisplayMetrics().density);
rvLetters.setPadding(basePad, 0, basePad, 0);
lettersSnapHelper = new PagerSnapHelper();
lettersSnapHelper.attachToRecyclerView(rvLetters);
// Add spacing between letters for off-screen effect
final int letterSpace = (int)(12 * getResources().getDisplayMetrics().density);
rvLetters.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull android.graphics.Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int pos = parent.getChildAdapterPosition(view);
if (pos == RecyclerView.NO_POSITION) return;
outRect.left = letterSpace;
outRect.right = letterSpace;
}
});
rvLetters.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
applyLetterTransforms(recyclerView);
}
@Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) applyLetterTransforms(recyclerView);
}
});
// Initial snap + dynamic side padding after first layout to keep center item centered
rvLetters.getViewTreeObserver().addOnGlobalLayoutListener(new android.view.ViewTreeObserver.OnGlobalLayoutListener() {
@Override public void onGlobalLayout() {
int w = rvLetters.getWidth();
if (w > 0) {
float d = getResources().getDisplayMetrics().density;
int itemPx = (int) (72 * d); // item_letter width
int letterSpace = (int) (12 * d);
int totalItem = itemPx + 2 * letterSpace;
int side = Math.max((int)(24 * d), (w - totalItem) / 2);
rvLetters.setPadding(side, 0, side, 0);
}
rvLetters.getViewTreeObserver().removeOnGlobalLayoutListener(this);
rvLetters.post(() -> { resnapLetters(); applyLetterTransforms(rvLetters); });
}
});
}
// Scale/alpha transform based on distance from center
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
@@ -142,6 +220,14 @@ public class GamesCoverDialogFragment extends DialogFragment {
localPaths[i] = new java.io.File(getCoversDir(), serial + ".png").getAbsolutePath();
}
// cache originals for sorting/filtering
origTitles = Arrays.copyOf(titles, titles.length);
origUris = Arrays.copyOf(uris, uris.length);
origCoverUrls = Arrays.copyOf(coverUrls, coverUrls.length);
origLocalPaths = Arrays.copyOf(localPaths, localPaths.length);
// restore sort pref if any
sortMode = prefs.getInt("covers_sort_mode", SORT_ALPHA);
adapter = new CoversAdapter(requireContext(), titles, coverUrls, localPaths, R.layout.item_coverflow,
position -> {
if (listener != null && position >= 0 && position < uris.length) {
@@ -155,6 +241,30 @@ public class GamesCoverDialogFragment extends DialogFragment {
}
});
rv.setAdapter(adapter);
// Build letters list if row present (RecyclerView variant)
if (rvLetters != null) buildLettersAndBind();
// Hook sort/search buttons if present
View btnSortV = root.findViewById(R.id.btn_sort);
if (btnSortV instanceof com.google.android.material.button.MaterialButton) {
com.google.android.material.button.MaterialButton btnSort = (com.google.android.material.button.MaterialButton) btnSortV;
updateSortButtonUi(btnSort);
btnSort.setOnClickListener(v -> {
sortMode = (sortMode == SORT_ALPHA) ? SORT_RECENT : SORT_ALPHA;
requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
.edit().putInt("covers_sort_mode", sortMode).apply();
applyFilterAndSort();
updateSortButtonUi(btnSort);
});
}
View btnSearch = root.findViewById(R.id.btn_search);
if (btnSearch != null) {
btnSearch.setOnClickListener(v -> showSearchDialog());
}
// apply initial sort/filter if needed
if (sortMode != SORT_ALPHA || (query != null && !query.isEmpty())) {
applyFilterAndSort();
}
// One-time tiny nudge to force snap/transform on some devices
rv.post(() -> {
if (!isAdded() || didInitialNudge) return;
@@ -192,11 +302,19 @@ public class GamesCoverDialogFragment extends DialogFragment {
String t = TitleResolver.resolveTitleForUri(requireContext(), uris[i], titles[i]);
if (t != null && !t.isEmpty() && i < titles.length && !t.equals(titles[i])) {
titles[i] = t;
if (origTitles != null && i < origTitles.length) origTitles[i] = t;
changed = true;
}
} catch (Throwable ignored) {}
}
if (changed && isAdded()) requireActivity().runOnUiThread(() -> adapter.notifyDataSetChanged());
if (changed && isAdded()) requireActivity().runOnUiThread(() -> {
if (sortMode != SORT_ALPHA || (query != null && !query.isEmpty())) {
applyFilterAndSort();
} else {
adapter.notifyDataSetChanged();
if (rvLetters != null) buildLettersAndBind();
}
});
}).start();
// Dynamically size items based on RecyclerView size and orientation
@@ -219,7 +337,18 @@ public class GamesCoverDialogFragment extends DialogFragment {
int widthFromHeight = (int) (availableH * ratio);
int widthFromWidth = (int) (rvW * (landscape ? 0.35f : 0.55f));
int itemWidth = Math.max(160, Math.min(widthFromHeight, widthFromWidth));
lastItemWidthPx = itemWidth;
adapter.setItemWidthPx(itemWidth);
// Center vertically in portrait by adjusting top/bottom padding
if (!landscape) {
int imageH = (int) (itemWidth / (567f / 878f));
int titlePx = (int) ((titleDp + extraDp) * density);
int contentH = imageH + titlePx;
int desiredPad = Math.max(vertPad, Math.max(0, (rvH - contentH) / 2));
rv.setPadding(sidePad, desiredPad, sidePad, desiredPad);
} else {
rv.setPadding(sidePad, vertPad, sidePad, vertPad);
}
// If user is scrolling, defer resnap until idle to avoid fighting gesture
if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
resnapToCenter(rv);
@@ -238,6 +367,267 @@ public class GamesCoverDialogFragment extends DialogFragment {
return root;
}
private void buildLettersAndBind() {
letters.clear();
boolean hasHash = false;
boolean[] present = new boolean[26];
if (titles != null) {
for (String t : titles) {
if (t == null) continue;
char c = firstLetter(t);
if (c >= 'A' && c <= 'Z') present[c - 'A'] = true;
else hasHash = true;
}
}
if (hasHash) letters.add('#');
for (int i = 0; i < 26; i++) if (present[i]) letters.add((char)('A'+i));
if (rvLetters != null) {
lettersAdapter = new LettersAdapter(letters, this::onLetterTapped);
rvLetters.setAdapter(lettersAdapter);
// Anchor to a large middle position for infinite wrap-around
int n = letters.size();
if (n > 0) {
int center = (1 << 29);
int startPos = center - (center % n);
llmLetters.scrollToPosition(startPos);
}
rvLetters.post(() -> { resnapLetters(); applyLetterTransforms(rvLetters); });
}
}
private void applyLetterTransforms(@NonNull RecyclerView recyclerView) {
int rvCenterX = (recyclerView.getLeft() + recyclerView.getRight()) / 2;
final float maxScale = 1.0f;
final float minScale = 0.85f;
final float maxAlpha = 1.0f;
final float minAlpha = 0.6f;
for (int i = 0; i < recyclerView.getChildCount(); i++) {
View child = recyclerView.getChildAt(i);
int childCenterX = (child.getLeft() + child.getRight()) / 2;
float dx = Math.abs(childCenterX - rvCenterX);
float norm = Math.min(1f, dx / (recyclerView.getWidth() * 0.5f));
float scale = maxScale - (maxScale - minScale) * norm;
float alpha = maxAlpha - (maxAlpha - minAlpha) * norm;
child.setScaleX(scale);
child.setScaleY(scale);
child.setAlpha(alpha);
}
}
private void buildLetterIndexLinear(@NonNull LinearLayout container) {
container.removeAllViews();
// Build present letters with normalization
java.util.LinkedHashSet<Character> set = new java.util.LinkedHashSet<>();
if (titles != null) {
for (String t : titles) {
char c = firstLetter(t);
if (c == '#') { set.add('#'); }
else if (c >= 'A' && c <= 'Z') set.add(c);
}
}
float d = getResources().getDisplayMetrics().density;
int padH = (int) (14 * d);
int padV = (int) (6 * d);
for (Character ch : set) {
TextView tv = new TextView(requireContext());
tv.setText(String.valueOf(ch));
tv.setTextSize(18);
tv.setTextColor(getResources().getColor(R.color.brand_primary));
tv.setPadding(padH, padV, padH, padV);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins((int)(8*d), 0, (int)(8*d), 0); // extra spacing
tv.setLayoutParams(lp);
tv.setOnClickListener(v -> onLetterTapped(ch));
container.addView(tv);
}
}
private void onLetterTapped(char letter) {
android.util.Log.d("LetterTap", "Letter tapped: " + letter + ", sortMode: " + sortMode + ", titles.length: " + (titles != null ? titles.length : 0));
// Force AZ sorting for predictable letter navigation
if (sortMode != SORT_ALPHA) {
android.util.Log.d("LetterTap", "Switching to ALPHA sort mode");
sortMode = SORT_ALPHA;
requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE)
.edit().putInt("covers_sort_mode", sortMode).apply();
pendingLetterJump = letter;
applyFilterAndSort();
} else {
android.util.Log.d("LetterTap", "Already in ALPHA mode, jumping to letter");
// Jump to first index for that letter in the current (alphabetical) list
jumpToLetter(letter);
}
// Center letters row on selected
if (rvLetters != null && letters != null && !letters.isEmpty()) {
int idx = letters.indexOf(letter);
if (idx >= 0) {
centerLettersOnIndex(idx);
}
}
}
private void centerLettersOnIndex(int idx) {
if (rvLetters == null || llmLetters == null) return;
View snapView = lettersSnapHelper != null ? lettersSnapHelper.findSnapView(llmLetters) : null;
int centerPos = (snapView != null) ? rvLetters.getChildAdapterPosition(snapView) : llmLetters.findFirstVisibleItemPosition();
if (centerPos == RecyclerView.NO_POSITION) centerPos = 0;
int n = letters != null ? letters.size() : 0;
if (n <= 0) return;
int centerIdx = centerPos % n;
int forward = (idx - centerIdx + n) % n;
int backward = (centerIdx - idx + n) % n;
int delta = (forward <= backward) ? forward : -backward;
llmLetters.scrollToPosition(centerPos + delta);
rvLetters.post(() -> { resnapLetters(); applyLetterTransforms(rvLetters); });
}
private void resnapLetters() {
if (rvLetters == null || llmLetters == null || lettersSnapHelper == null) return;
View snap = lettersSnapHelper.findSnapView(llmLetters);
if (snap == null) return;
int[] dist = lettersSnapHelper.calculateDistanceToFinalSnap(llmLetters, snap);
if (dist != null && (dist[0] != 0 || dist[1] != 0)) rvLetters.scrollBy(dist[0], dist[1]);
}
private void updateSortButtonUi(@NonNull com.google.android.material.button.MaterialButton btn) {
btn.setIconResource(R.drawable.sort_24px);
boolean alpha = (sortMode == SORT_ALPHA);
btn.setText(alpha ? "AZ" : "RECENT");
btn.setContentDescription(alpha ? "Sort AZ" : "Sort Recent");
}
private void showSearchDialog() {
final EditText input = new EditText(requireContext());
input.setHint("Search games");
int pad = (int) (16 * getResources().getDisplayMetrics().density);
input.setPadding(pad, pad, pad, pad);
new com.google.android.material.dialog.MaterialAlertDialogBuilder(requireContext(),
com.google.android.material.R.style.ThemeOverlay_Material3_MaterialAlertDialog)
.setTitle("Search")
.setView(input)
.setNegativeButton("Clear", (d, w) -> {
query = null;
applyFilterAndSort();
})
.setPositiveButton("Apply", (d, w) -> {
query = input.getText() != null ? input.getText().toString().trim() : null;
if (query != null && query.isEmpty()) query = null;
applyFilterAndSort();
})
.show();
}
private void jumpToLetter(char letterRaw) {
android.util.Log.d("LetterJump", "jumpToLetter called with: " + letterRaw);
if (titles == null || titles.length == 0) {
android.util.Log.d("LetterJump", "No titles available");
return;
}
char letter = Character.toUpperCase(letterRaw);
int target = -1;
for (int i = 0; i < titles.length; i++) {
char c = firstLetter(titles[i]);
if ((letter == '#') ? (c == '#') : (c == letter)) {
target = i;
android.util.Log.d("LetterJump", "Found target at index " + i + " for letter " + letter + ", title: " + titles[i]);
break;
}
}
if (target >= 0) {
android.util.Log.d("LetterJump", "Scrolling to index: " + target);
scrollToIndex(target);
} else {
android.util.Log.d("LetterJump", "No target found for letter: " + letter);
}
}
private void scrollToIndex(int idx) {
if (llm == null || rv == null || titles == null || titles.length == 0) return;
View snap = snapHelper != null ? snapHelper.findSnapView(llm) : null;
int centerPos = (snap != null) ? rv.getChildAdapterPosition(snap) : llm.findFirstVisibleItemPosition();
if (centerPos == RecyclerView.NO_POSITION) centerPos = 0;
int n = titles.length;
int centerIdx = centerPos % n;
int forward = (idx - centerIdx + n) % n;
int backward = (centerIdx - idx + n) % n;
int delta = (forward <= backward) ? forward : -backward;
llm.scrollToPosition(centerPos + delta);
rv.post(() -> { resnapToCenter(rv); applyCoverflowTransforms(rv); });
}
private void applyFilterAndSort() {
int n = origTitles != null ? origTitles.length : 0;
ArrayList<Integer> idxs = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
if (query == null || query.isEmpty()) {
idxs.add(i);
} else {
String t = origTitles[i] != null ? origTitles[i] : "";
if (t.toLowerCase(Locale.ROOT).contains(query.toLowerCase(Locale.ROOT))) idxs.add(i);
}
}
SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
if (sortMode == SORT_RECENT) {
idxs.sort((a, b) -> {
long ta = prefs.getLong("last_played:" + origUris[a], 0L);
long tb = prefs.getLong("last_played:" + origUris[b], 0L);
if (ta == tb) return origTitles[a].compareToIgnoreCase(origTitles[b]);
return Long.compare(tb, ta);
});
} else {
idxs.sort(Comparator.comparing(i -> {
String t = origTitles[i];
return t == null ? "" : t.toLowerCase(Locale.ROOT);
}));
}
titles = new String[idxs.size()];
uris = new String[idxs.size()];
coverUrls = new String[idxs.size()];
localPaths = new String[idxs.size()];
for (int k = 0; k < idxs.size(); k++) {
int i = idxs.get(k);
titles[k] = origTitles[i];
uris[k] = origUris[i];
coverUrls[k] = origCoverUrls[i];
localPaths[k] = origLocalPaths[i];
}
adapter = new CoversAdapter(requireContext(), titles, coverUrls, localPaths, R.layout.item_coverflow,
position -> {
if (listener != null && position >= 0 && position < uris.length) {
listener.onGameSelected(uris[position]);
dismissAllowingStateLoss();
}
},
position -> {
if (position >= 0 && position < uris.length) {
showGameSettings(titles[position], uris[position]);
}
});
rv.setAdapter(adapter);
if (lastItemWidthPx > 0) adapter.setItemWidthPx(lastItemWidthPx);
int n2 = titles.length;
if (n2 > 0) {
int center = (1 << 29);
int startPos = center - (center % n2);
llm.scrollToPosition(startPos);
}
rv.post(() -> { resnapToCenter(rv); applyCoverflowTransforms(rv); });
if (rvLetters != null) {
buildLettersAndBind();
if (pendingLetterJump != null) {
final char l = pendingLetterJump;
pendingLetterJump = null;
rv.postDelayed(() -> {
jumpToLetter(l);
if (letters != null) {
int idx = letters.indexOf(l);
if (idx >= 0) centerLettersOnIndex(idx);
}
}, 10);
}
}
}
private void applyCoverflowTransforms(@NonNull RecyclerView recyclerView) {
int rvCenterX = (recyclerView.getLeft() + recyclerView.getRight()) / 2;
boolean landscape = getResources().getConfiguration().orientation == android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -0,0 +1,69 @@
package com.izzy2lost.psx2;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class LettersAdapter extends RecyclerView.Adapter<LettersAdapter.VH> {
public interface OnClick {
void onClick(char letter);
}
private final List<Character> letters;
private final OnClick onClick;
public LettersAdapter(List<Character> letters, OnClick onClick) {
this.letters = letters;
this.onClick = onClick;
setHasStableIds(true);
}
@Override
public long getItemId(int position) {
// Ensure uniqueness across the infinite range by including position
return position;
}
@NonNull
@Override
public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_letter, parent, false);
return new VH(v);
}
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
int n = letters != null ? letters.size() : 0;
if (n == 0) return;
int real = position % n;
char ch = letters.get(real);
holder.text.setText(String.valueOf(ch));
holder.itemView.setOnClickListener(v -> {
android.util.Log.d("LettersAdapter", "Letter clicked: " + ch + " at position " + position);
if (onClick != null) {
onClick.onClick(ch);
} else {
android.util.Log.d("LettersAdapter", "onClick is null!");
}
});
}
@Override
public int getItemCount() {
return (letters != null && !letters.isEmpty()) ? Integer.MAX_VALUE : 0;
}
static class VH extends RecyclerView.ViewHolder {
final TextView text;
VH(@NonNull View itemView) {
super(itemView);
text = itemView.findViewById(R.id.text_letter);
}
}
}
@@ -246,6 +246,11 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
// Enable immersive mode to hide navigation and status bars
private void enableImmersiveMode() {
hideStatusBar();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -297,6 +302,11 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
if (!TextUtils.isEmpty(gameUri)) {
// Avoid any pre-VM native calls here; just set the game and launch.
m_szGamefile = gameUri;
// Record last played timestamp for sorting
try {
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
prefs.edit().putLong("last_played:" + gameUri, System.currentTimeMillis()).apply();
} catch (Throwable ignored) {}
restartEmuThread();
}
}
@@ -372,7 +382,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
getSupportActionBar().hide();
}
setContentView(R.layout.activity_main);
hideStatusBar();
enableImmersiveMode();
// Setup back button handler
setupBackPressedHandler();
@@ -397,14 +407,10 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Ensure consistent ripple across all MaterialButtons
tintAllMaterialButtonOutlines();
// Settings are already applied in Initialize() -> loadAndApplySettings()
// No need to call applySavedSettings() again here
// Apply orientation-specific constraints once at startup
int currentOrientation = getResources().getConfiguration().orientation;
applyConstraintsForOrientation(currentOrientation);
// Prompt for BIOS if missing
maybePromptForBios();
@@ -437,10 +443,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
getOnBackPressedDispatcher().addCallback(this, callback);
}
private void makeButtonTouch() {
MaterialButton btn_file = findViewById(R.id.btn_file);
if(btn_file != null) {
@@ -493,8 +495,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
// Games button handled above
// Settings button opens dialog
MaterialButton btn_settings = findViewById(R.id.btn_settings);
if (btn_settings != null) {
@@ -513,10 +513,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
// HUD toggle moved to Settings (Developer section)
// Hide UI button (removed - functionality moved to toggle button)
// Small unhide button (appears when all UI is hidden)
MaterialButton btn_unhide_ui = findViewById(R.id.btn_unhide_ui);
if(btn_unhide_ui != null) {
@@ -525,9 +521,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
//////
// RENDERER
MaterialButton btn_ogl = findViewById(R.id.btn_ogl);
if(btn_ogl != null) {
btn_ogl.setOnClickListener(v -> {
@@ -588,9 +582,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
//////
// PAD
MaterialButton btn_pad_select = findViewById(R.id.btn_pad_select);
if(btn_pad_select != null) {
btn_pad_select.setOnTouchListener((v, event) -> {
@@ -605,7 +597,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
return true;
});
}
MaterialButton btn_pad_a = findViewById(R.id.btn_pad_a);
if(btn_pad_a != null) {
btn_pad_a.setOnTouchListener((v, event) -> {
@@ -635,8 +626,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
////
//// Shoulder buttons
MaterialButton btn_pad_l1 = findViewById(R.id.btn_pad_l1);
if(btn_pad_l1 != null) {
btn_pad_l1.setOnTouchListener((v, event) -> {
@@ -682,8 +672,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
////
//// D-Pad
final int PAD_L_UP = 110;
final int PAD_L_RIGHT = 111;
final int PAD_L_DOWN = 112;
@@ -796,8 +785,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
});
}
////
//// D-Pad buttons
MaterialButton btn_pad_dir_top = findViewById(R.id.btn_pad_dir_top);
if(btn_pad_dir_top != null) {
btn_pad_dir_top.setOnTouchListener((v, event) -> {
@@ -1204,6 +1192,10 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
if(_intent != null) {
m_szGamefile = _intent.getDataString();
if(!TextUtils.isEmpty(m_szGamefile)) {
try {
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
prefs.edit().putLong("last_played:" + m_szGamefile, System.currentTimeMillis()).apply();
} catch (Throwable ignored) {}
restartEmuThread();
}
}
@@ -1393,7 +1385,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
mHIDDeviceManager.setFrozen(false);
}
// Re-assert full screen when returning to the activity
hideStatusBar();
enableImmersiveMode();
updateUiForControllerPresence();
}
@@ -1423,8 +1415,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
android.os.Process.killProcess(appPid);
}
//////////////////////////////////////////////////////////////////////////////////////////////
public void Initialize() {
NativeApp.initializeOnce(getApplicationContext());
@@ -1441,8 +1431,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Initialize HID device manager for USB and Bluetooth controllers
mHIDDeviceManager.initialize(true, true);
// Avoid forcing renderer init when no game/surface is active.
// Renderer is applied on game start (restartEmuThread) and from settings when appropriate.
}
private void setSurfaceView(Object p_value) {
@@ -1499,8 +1487,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
// Use only our controller handler - disable SDL fallback to avoid conflicts
@@ -1581,7 +1567,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Asset copy helpers used on first launch to seed default resources
private void copyAssetAll(Context context, String srcPath) {
AssetManager assetMgr = context.getAssets();
@@ -1630,8 +1615,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
@Override
public void onBackPressed() {
// Fallback for older Android versions
@@ -1658,8 +1641,6 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
.show();
}
// ControllerInputHandler.ControllerInputListener implementation
@Override
public void onControllerButtonPressed(int controllerId, int button, boolean pressed) {
@@ -1746,9 +1727,7 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
private void handleAnalogInput(int axis, float value) {
// Convert analog input to button presses for the native interface
// This matches how AetherSX2 handles analog input
// Convert analog input to button presses for the native interface
// For analog sticks, only send positive values (negative values are handled by opposite direction)
int intensity = Math.max(0, Math.round(Math.abs(value) * 255));
boolean pressed = Math.abs(value) > 0.1f;