From ab69fd1aa43a83eec79f652caca60bf61f43e353 Mon Sep 17 00:00:00 2001 From: StreamPlayer Bot Date: Mon, 9 Feb 2026 22:05:54 -0300 Subject: [PATCH] feat: Add persistent scrollbar to events list - Enable fadeScrollbars=false in RecyclerView - Improve visibility of scrollbar fix: Prevent navigation focus escape at end of list - Implement custom LinearLayoutManager to intercept focus search - Block FOCUS_DOWN action at the last item - Remove legacy OnKeyListener and OnScrollListener --- CHANGELOG-v10.1.7.md | 22 +++++++++ app/build.gradle | 4 +- .../java/com/streamplayer/MainActivity.java | 48 +++++-------------- app/src/main/res/layout/activity_main.xml | 1 + 4 files changed, 37 insertions(+), 38 deletions(-) create mode 100644 CHANGELOG-v10.1.7.md diff --git a/CHANGELOG-v10.1.7.md b/CHANGELOG-v10.1.7.md new file mode 100644 index 0000000..86a4d68 --- /dev/null +++ b/CHANGELOG-v10.1.7.md @@ -0,0 +1,22 @@ +# StreamPlayer v10.1.7 - Corrección de Navegación y Scrollbar Permanente + +## Correcciones Implementadas + +### 1. Barra de Desplazamiento Permanente +- **Feature**: Se agregó `android:fadeScrollbars="false"` al `RecyclerView` de eventos. +- **Beneficio**: La barra de desplazamiento ahora es visible permanentemente, permitiendo al usuario saber su posición (inicio, medio, final) en todo momento sin tener que interactuar primero. + +### 2. Navegación al Final de la Lista (Bug Fix) +- **Problema**: Al presionar "abajo" en el último evento, el foco saltaba involuntariamente a la sección de canales. +- **Solución**: Se implementó un `LinearLayoutManager` personalizado que intercepta la búsqueda de foco (`onInterceptFocusSearch`). +- **Detalle**: Cuando se detecta `FOCUS_DOWN` en el último elemento de la lista, la acción se bloquea, manteniendo al usuario en la lista de eventos. +- **Limpieza**: Se eliminaron los `OnKeyListener` y `OnScrollListener` anteriores que eran menos efectivos. + +## Archivos Modificados + +### MainActivity.java +- Implementación de `LinearLayoutManager` anónimo con `onInterceptFocusSearch`. +- Eliminación de listeners redundantes. + +### activity_main.xml +- `android:fadeScrollbars="false"` añadido a `content_list`. diff --git a/app/build.gradle b/app/build.gradle index df85da8..080c5fb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.streamplayer" minSdk 21 targetSdk 35 - versionCode 100102 - versionName "10.1.2" + versionCode 100107 + versionName "10.1.7" buildConfigField "String", "DEVICE_REGISTRY_URL", '"http://194.163.191.200:4000"' } diff --git a/app/src/main/java/com/streamplayer/MainActivity.java b/app/src/main/java/com/streamplayer/MainActivity.java index 774225a..9c82258 100644 --- a/app/src/main/java/com/streamplayer/MainActivity.java +++ b/app/src/main/java/com/streamplayer/MainActivity.java @@ -73,7 +73,18 @@ public class MainActivity extends AppCompatActivity { eventAdapter = new EventAdapter(event -> openPlayer(event.getTitle(), event.getPageUrl())); eventRepository = new EventRepository(); channelLayoutManager = new GridLayoutManager(this, getSpanCount()); - eventLayoutManager = new LinearLayoutManager(this); + eventLayoutManager = new LinearLayoutManager(this) { + @Override + public View onInterceptFocusSearch(View focused, int direction) { + if (direction == View.FOCUS_DOWN) { + int pos = getPosition(focused); + if (pos == getItemCount() - 1) { + return focused; + } + } + return super.onInterceptFocusSearch(focused, direction); + } + }; sections = buildSections(); sectionList.setLayoutManager(new LinearLayoutManager(this)); @@ -192,41 +203,6 @@ public class MainActivity extends AppCompatActivity { // Clear existing listeners contentList.clearOnScrollListeners(); - // Prevent navigation out of events section via remote control - contentList.setOnKeyListener((v, keyCode, event) -> { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { - int totalItemCount = eventLayoutManager.getItemCount(); - if (totalItemCount > 0) { - int lastVisiblePosition = eventLayoutManager.findLastVisibleItemPosition(); - // Prevent going down if we're at or near the last item - if (lastVisiblePosition >= totalItemCount - 1) { - // Consume the event to prevent navigation - return true; - } - } - } - } - return false; - }); - - // Also prevent scroll-based navigation - contentList.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (dy > 0) { // Scrolling down - int totalItemCount = eventLayoutManager.getItemCount(); - if (totalItemCount > 0) { - int lastCompletelyVisiblePosition = eventLayoutManager.findLastCompletelyVisibleItemPosition(); - if (lastCompletelyVisiblePosition == totalItemCount - 1) { - recyclerView.stopScroll(); - } - } - } - } - }); - if (cachedEvents.isEmpty()) { loadEvents(false); } else { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 0509337..37eef73 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -129,6 +129,7 @@ android:layout_weight="1" android:overScrollMode="never" android:scrollbars="vertical" + android:fadeScrollbars="false" android:scrollbarStyle="insideInset" android:scrollbarThumbVertical="@drawable/scrollbar_vertical" android:scrollbarTrackVertical="@color/scrollbar_track"