diff --git a/src/App.tsx b/src/App.tsx index 6e3b756..e494c68 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -86,8 +86,9 @@ export function App() { const isQuit = keybind.match("quit", keyEvent); const isInverting = keybind.isInverting(keyEvent); - // only handling top navigation here, cycle through tabs, just to high priority(player) all else to be handled in each tab + // unified navigation: left->right, top->bottom across all tabs if (nav.activeDepth() == 0) { + // at top level: cycle through tabs if ( (isCycle && !isInverting) || (isDown && !isInverting) || @@ -104,6 +105,7 @@ export function App() { nav.prevTab(); return; } + // dive out to first pane if ( (isDive && !isInverting) || (isOut && isInverting) || @@ -112,8 +114,8 @@ export function App() { ) { nav.setActiveDepth(1); } - } - if (nav.activeDepth() == 1) { + } else { + // in panes: navigate between them if ( (isDive && isInverting) || (isOut && !isInverting) || @@ -121,6 +123,10 @@ export function App() { (isLeft && !isInverting) ) { nav.setActiveDepth(0); + } else if (isDown && !isInverting) { + nav.nextPane(); + } else if (isUp && isInverting) { + nav.prevPane(); } } }, diff --git a/src/context/NavigationContext.tsx b/src/context/NavigationContext.tsx index 8ef851a..fed079c 100644 --- a/src/context/NavigationContext.tsx +++ b/src/context/NavigationContext.tsx @@ -17,7 +17,7 @@ export const { use: useNavigation, provider: NavigationProvider } = ), ); - //conveniences + // unified navigation: left->right, top->bottom across all tabs const nextTab = () => { if (activeTab() >= TabsCount) { setActiveTab(1); @@ -31,10 +31,19 @@ export const { use: useNavigation, provider: NavigationProvider } = setActiveTab(TabsCount); return; } - setActiveTab(activeTab() - 1); }; + const nextPane = () => { + // move to next pane in same tab, wrap around + setActiveDepth((prev) => (prev % TabsCount) + 1); + }; + + const prevPane = () => { + // move to previous pane in same tab, wrap around + setActiveDepth((prev) => (prev - 2 + TabsCount) % TabsCount + 1); + }; + return { activeTab, activeDepth, @@ -44,6 +53,8 @@ export const { use: useNavigation, provider: NavigationProvider } = setInputFocused, nextTab, prevTab, + nextPane, + prevPane, }; }, }); diff --git a/src/pages/Discover/DiscoverPage.tsx b/src/pages/Discover/DiscoverPage.tsx index ba409aa..47f9473 100644 --- a/src/pages/Discover/DiscoverPage.tsx +++ b/src/pages/Discover/DiscoverPage.tsx @@ -31,6 +31,7 @@ export function DiscoverPage() { const isUp = keybind.match("up", keyEvent); const isCycle = keybind.match("cycle", keyEvent); const isSelect = keybind.match("select", keyEvent); + const isInverting = keybind.isInverting(keyEvent); if (isSelect) { const filteredPodcasts = discoverStore.filteredPodcasts(); @@ -40,15 +41,20 @@ export function DiscoverPage() { return; } + // don't handle pane navigation here - unified in App.tsx + if (nav.activeDepth() !== DiscoverPagePaneType.SHOWS) return; + const filteredPodcasts = discoverStore.filteredPodcasts(); if (filteredPodcasts.length === 0) return; - if (isDown) { + if (isDown && !isInverting()) { setShowIndex((i) => (i + 1) % filteredPodcasts.length); - } else if (isUp) { + } else if (isUp && isInverting()) { setShowIndex((i) => (i - 1 + filteredPodcasts.length) % filteredPodcasts.length); - } else if (isCycle) { + } else if ((isCycle && !isInverting()) || (isDown && !isInverting())) { setShowIndex((i) => (i + 1) % filteredPodcasts.length); + } else if ((isCycle && isInverting()) || (isUp && isInverting())) { + setShowIndex((i) => (i - 1 + filteredPodcasts.length) % filteredPodcasts.length); } }, { release: false }, diff --git a/src/pages/Feed/FeedPage.tsx b/src/pages/Feed/FeedPage.tsx index 2badd7e..fbbd6fb 100644 --- a/src/pages/Feed/FeedPage.tsx +++ b/src/pages/Feed/FeedPage.tsx @@ -41,6 +41,7 @@ export function FeedPage() { const isUp = keybind.match("up", keyEvent); const isCycle = keybind.match("cycle", keyEvent); const isSelect = keybind.match("select", keyEvent); + const isInverting = keybind.isInverting(keyEvent); if (isSelect) { const episodes = allEpisodes(); @@ -50,15 +51,20 @@ export function FeedPage() { return; } + // don't handle pane navigation here - unified in App.tsx + if (nav.activeDepth() !== FeedPaneType.FEED) return; + const episodes = allEpisodes(); if (episodes.length === 0) return; - if (isDown) { + if (isDown && !isInverting()) { setFocusedIndex((i) => (i + 1) % episodes.length); - } else if (isUp) { + } else if (isUp && isInverting()) { setFocusedIndex((i) => (i - 1 + episodes.length) % episodes.length); - } else if (isCycle) { + } else if ((isCycle && !isInverting()) || (isDown && !isInverting())) { setFocusedIndex((i) => (i + 1) % episodes.length); + } else if ((isCycle && isInverting()) || (isUp && isInverting())) { + setFocusedIndex((i) => (i - 1 + episodes.length) % episodes.length); } }, { release: false }, diff --git a/src/pages/MyShows/MyShowsPage.tsx b/src/pages/MyShows/MyShowsPage.tsx index 7a983bf..066dcf1 100644 --- a/src/pages/MyShows/MyShowsPage.tsx +++ b/src/pages/MyShows/MyShowsPage.tsx @@ -42,10 +42,10 @@ export function MyShowsPage() { const isUp = keybind.match("up", keyEvent); const isCycle = keybind.match("cycle", keyEvent); const isSelect = keybind.match("select", keyEvent); + const isInverting = keybind.isInverting(keyEvent); const shows = feedStore.getFilteredFeeds(); const episodesList = episodes(); - const selected = selectedShow(); if (isSelect) { if (shows.length > 0 && showIndex() < shows.length) { @@ -57,23 +57,18 @@ export function MyShowsPage() { return; } - if (shows.length > 0) { - if (isDown) { - setShowIndex((i) => (i + 1) % shows.length); - } else if (isUp) { - setShowIndex((i) => (i - 1 + shows.length) % shows.length); - } else if (isCycle) { - setShowIndex((i) => (i + 1) % shows.length); - } - } + // don't handle pane navigation here - unified in App.tsx + if (nav.activeDepth() !== MyShowsPaneType.EPISODES) return; if (episodesList.length > 0) { - if (isDown) { + if (isDown && !isInverting()) { setEpisodeIndex((i) => (i + 1) % episodesList.length); - } else if (isUp) { + } else if (isUp && isInverting()) { setEpisodeIndex((i) => (i - 1 + episodesList.length) % episodesList.length); - } else if (isCycle) { + } else if ((isCycle && !isInverting()) || (isDown && !isInverting())) { setEpisodeIndex((i) => (i + 1) % episodesList.length); + } else if ((isCycle && isInverting()) || (isUp && isInverting())) { + setEpisodeIndex((i) => (i - 1 + episodesList.length) % episodesList.length); } } }, diff --git a/src/pages/Player/PlayerPage.tsx b/src/pages/Player/PlayerPage.tsx index 131cbf5..d4a4654 100644 --- a/src/pages/Player/PlayerPage.tsx +++ b/src/pages/Player/PlayerPage.tsx @@ -23,6 +23,8 @@ export function PlayerPage() { onMount(() => { useKeyboard( (keyEvent: any) => { + const isInverting = keybind.isInverting(keyEvent); + if (keybind.match("audio-toggle", keyEvent)) { audio.togglePlayback(); return; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index fd6d14e..6b767b5 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -36,6 +36,7 @@ export function SearchPage() { const isUp = keybind.match("up", keyEvent); const isCycle = keybind.match("cycle", keyEvent); const isSelect = keybind.match("select", keyEvent); + const isInverting = keybind.isInverting(keyEvent); if (isSelect) { const results = searchStore.results(); @@ -45,15 +46,20 @@ export function SearchPage() { return; } + // don't handle pane navigation here - unified in App.tsx + if (nav.activeDepth() !== SearchPaneType.RESULTS) return; + const results = searchStore.results(); if (results.length === 0) return; - if (isDown) { + if (isDown && !isInverting()) { setResultIndex((i) => (i + 1) % results.length); - } else if (isUp) { + } else if (isUp && isInverting()) { setResultIndex((i) => (i - 1 + results.length) % results.length); - } else if (isCycle) { + } else if ((isCycle && !isInverting()) || (isDown && !isInverting())) { setResultIndex((i) => (i + 1) % results.length); + } else if ((isCycle && isInverting()) || (isUp && isInverting())) { + setResultIndex((i) => (i - 1 + results.length) % results.length); } }, { release: false }, diff --git a/src/pages/Settings/SettingsPage.tsx b/src/pages/Settings/SettingsPage.tsx index 4a01730..937fb6f 100644 --- a/src/pages/Settings/SettingsPage.tsx +++ b/src/pages/Settings/SettingsPage.tsx @@ -45,20 +45,19 @@ export function SettingsPage() { const isUp = keybind.match("up", keyEvent); const isCycle = keybind.match("cycle", keyEvent); const isSelect = keybind.match("select", keyEvent); + const isInverting = keybind.isInverting(keyEvent); - if (isSelect) { + // don't handle pane navigation here - unified in App.tsx + if (nav.activeDepth() < 1 || nav.activeDepth() > SettingsPaneCount) return; + + if (isDown && !isInverting()) { nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1); - return; - } - - const nextDepth = isDown - ? (nav.activeDepth() % SettingsPaneCount) + 1 - : (nav.activeDepth() - 2 + SettingsPaneCount) % SettingsPaneCount + 1; - - if (isCycle) { + } else if (isUp && isInverting()) { + nav.setActiveDepth((nav.activeDepth() - 2 + SettingsPaneCount) % SettingsPaneCount + 1); + } else if ((isCycle && !isInverting()) || (isDown && !isInverting())) { nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1); - } else { - nav.setActiveDepth(nextDepth); + } else if ((isCycle && isInverting()) || (isUp && isInverting())) { + nav.setActiveDepth((nav.activeDepth() - 2 + SettingsPaneCount) % SettingsPaneCount + 1); } }, { release: false },