Skip to content

Conversation

@pierpo
Copy link
Member

@pierpo pierpo commented Oct 15, 2024

No description provided.

@pierpo pierpo force-pushed the feat/add-stick-to-center branch from 53a3778 to 6ad08a7 Compare October 15, 2024 17:41
@robmim
Copy link
Contributor

robmim commented Jul 3, 2025

@pierpo @slvvn

what about a solution like this....

Enregistrement.d.ecran.le.2025-07-03.a.14.mp4
import React, { useEffect, useRef, useState, createRef } from "react";
import { StyleSheet, Text, View, Platform, Dimensions } from "react-native";
import KeyEvent from "react-native-keyevent";
import {
  SpatialNavigationRoot,
  SpatialNavigationFocusableView,
} from "react-tv-space-navigation";

const ROWS = 1;
const COLS = 50;
const PATCH_SIZE = 7;
const GAP = 10;
const WINDOW_WIDTH = Dimensions.get("window").width;
const CELL_SIZE =
  (WINDOW_WIDTH - (PATCH_SIZE - 1) * GAP - 2 * GAP) / PATCH_SIZE;

const WorkingGrid: React.FC = () => {
  const [focused, setFocused] = useState<{ col: number }>({ col: 0 });

  // UseRef for stable refs across renders
  const patchRefs = useRef(
    Array.from({ length: PATCH_SIZE }, () => createRef<any>())
  ).current;

  const getPatchLeft = () => {
    const half = Math.floor(PATCH_SIZE / 2);
    let left = Math.max(0, Math.min(focused.col - half, COLS - PATCH_SIZE));
    if (focused.col < half) left = 0;
    if (focused.col > COLS - half - 1) left = COLS - PATCH_SIZE;
    return left;
  };
  const patchLeft = getPatchLeft();

  // Move actual focus so isFocused from SpatialNavigationFocusableView works!
  useEffect(() => {
    const j = focused.col - patchLeft;
    if (j >= 0 && j < PATCH_SIZE) {
      const ref = patchRefs[j].current;
      if (ref && typeof ref.focus === "function") {
        ref.focus();
      }
    }
  }, [focused.col, patchLeft, patchRefs]);

  useEffect(() => {
    if (Platform.OS !== "android") return;
    KeyEvent.onKeyDownListener((keyEvent) => {
      setFocused((curr) => {
        let { col } = curr;
        switch (keyEvent.keyCode) {
          case 21: // LEFT
            col = Math.max(0, col - 1);
            break;
          case 22: // RIGHT
            col = Math.min(COLS - 1, col + 1);
            break;
        }
        return { col };
      });
    });
    return () => KeyEvent.removeKeyDownListener();
  }, []);

  return (
    <SpatialNavigationRoot>
      <View style={styles.viewport}>
        <View
          style={[
            styles.patch,
            {
              width: WINDOW_WIDTH,
              height: CELL_SIZE + 2 * GAP,
              left: 0,
              top: 100,
              paddingHorizontal: GAP,
              paddingVertical: GAP,
            },
          ]}
        >
          <View style={[styles.row, { gap: GAP }]}>
            {[...Array(PATCH_SIZE)].map((_, j) => {
              const colIdx = patchLeft + j;
              if (colIdx >= COLS)
                return (
                  <View key={j} style={[styles.cell, { width: CELL_SIZE }]} />
                );
              return (
                <SpatialNavigationFocusableView
                  key={j}
                  ref={patchRefs[j]}
                  onFocus={() => {
                    setFocused((curr) => {
                      if (curr.col !== colIdx) {
                        return { col: colIdx };
                      }
                      return curr;
                    });
                  }}
                  onSelect={() => {}}
                >
                  {({ isFocused }) => (
                    <View
                      style={[
                        styles.cell,
                        { width: CELL_SIZE },
                        isFocused ? styles.selectedCell : null,
                      ]}
                    >
                      <Text
                        style={[
                          styles.cellText,
                          isFocused ? styles.selectedText : null,
                        ]}
                      >
                        {1},{colIdx + 1}
                      </Text>
                    </View>
                  )}
                </SpatialNavigationFocusableView>
              );
            })}
          </View>
        </View>
      </View>
    </SpatialNavigationRoot>
  );
};

const styles = StyleSheet.create({
  viewport: {
    flex: 1,
    backgroundColor: "#101010",
    alignItems: "flex-start",
    justifyContent: "flex-start",
  },
  patch: {
    position: "absolute",
    overflow: "visible",
    backgroundColor: "#222",
    borderWidth: 2,
    borderColor: "#333",
  },
  row: {
    flexDirection: "row",
    width: "100%",
    height: "100%",
  },
  cell: {
    height: "100%",
    justifyContent: "center",
    alignItems: "center",
    borderWidth: 3,
    borderColor: "#555",
    backgroundColor: "#222",
    borderRadius: 10,
    flexShrink: 0,
    flexGrow: 0,
  },
  selectedCell: {
    borderColor: "#33aaff",
    backgroundColor: "#135",
  },
  cellText: {
    color: "#fff",
    fontSize: 16,
  },
  selectedText: {
    color: "#33aaff",
    fontWeight: "bold",
  },
});

export default WorkingGrid;

@Messanga11
Copy link

Please do you have any update here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants