temp keyboard handling
This commit is contained in:
@@ -2,13 +2,14 @@
|
||||
* DiscoverPage component - Main discover/browse interface for PodTUI
|
||||
*/
|
||||
|
||||
import { createSignal, For, Show } from "solid-js";
|
||||
import { createSignal, For, Show, onMount } from "solid-js";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { useDiscoverStore, DISCOVER_CATEGORIES } from "@/stores/discover";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { PodcastCard } from "./PodcastCard";
|
||||
import { SelectableBox, SelectableText } from "@/components/Selectable";
|
||||
import { useNavigation } from "@/context/NavigationContext";
|
||||
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
|
||||
|
||||
enum DiscoverPagePaneType {
|
||||
CATEGORIES = 1,
|
||||
@@ -21,6 +22,36 @@ export function DiscoverPage() {
|
||||
const [showIndex, setShowIndex] = createSignal(0);
|
||||
const [categoryIndex, setCategoryIndex] = createSignal(0);
|
||||
const nav = useNavigation();
|
||||
const keybind = useKeybinds();
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isDown = keybind.match("down", keyEvent);
|
||||
const isUp = keybind.match("up", keyEvent);
|
||||
const isEnter = keyEvent.name === "Enter" || keyEvent.name === " ";
|
||||
const isSpace = keyEvent.name === " ";
|
||||
|
||||
if (isEnter || isSpace) {
|
||||
const filteredPodcasts = discoverStore.filteredPodcasts();
|
||||
if (filteredPodcasts.length > 0 && showIndex() < filteredPodcasts.length) {
|
||||
setShowIndex(showIndex() + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredPodcasts = discoverStore.filteredPodcasts();
|
||||
if (filteredPodcasts.length === 0) return;
|
||||
|
||||
if (isDown && showIndex() < filteredPodcasts.length - 1) {
|
||||
setShowIndex(showIndex() + 1);
|
||||
} else if (isUp && showIndex() > 0) {
|
||||
setShowIndex(showIndex() - 1);
|
||||
}
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
const handleCategorySelect = (categoryId: string) => {
|
||||
discoverStore.setSelectedCategory(categoryId);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Reverse chronological order, grouped by date
|
||||
*/
|
||||
|
||||
import { createSignal, For, Show } from "solid-js";
|
||||
import { createSignal, For, Show, onMount } from "solid-js";
|
||||
import { useFeedStore } from "@/stores/feed";
|
||||
import { format } from "date-fns";
|
||||
import type { Episode } from "@/types/episode";
|
||||
@@ -13,6 +13,8 @@ import { SelectableBox, SelectableText } from "@/components/Selectable";
|
||||
import { useNavigation } from "@/context/NavigationContext";
|
||||
import { LoadingIndicator } from "@/components/LoadingIndicator";
|
||||
import { TABS } from "@/utils/navigation";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { KeybindProvider, useKeybinds } from "@/context/KeybindContext";
|
||||
|
||||
enum FeedPaneType {
|
||||
FEED = 1,
|
||||
@@ -29,6 +31,37 @@ export function FeedPage() {
|
||||
string | undefined
|
||||
>();
|
||||
const allEpisodes = () => feedStore.getAllEpisodesChronological();
|
||||
const keybind = useKeybinds();
|
||||
const [focusedIndex, setFocusedIndex] = createSignal(0);
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isDown = keybind.match("down", keyEvent);
|
||||
const isUp = keybind.match("up", keyEvent);
|
||||
const isEnter = keyEvent.name === "Enter" || keyEvent.name === " ";
|
||||
const isSpace = keyEvent.name === " ";
|
||||
|
||||
if (isEnter || isSpace) {
|
||||
const episodes = allEpisodes();
|
||||
if (episodes.length > 0 && episodes[focusedIndex()]) {
|
||||
setSelectedEpisodeID(episodes[focusedIndex()].episode.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const episodes = allEpisodes();
|
||||
if (episodes.length === 0) return;
|
||||
|
||||
if (isDown && focusedIndex() < episodes.length - 1) {
|
||||
setFocusedIndex(focusedIndex() + 1);
|
||||
} else if (isUp && focusedIndex() > 0) {
|
||||
setFocusedIndex(focusedIndex() - 1);
|
||||
}
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
const formatDate = (date: Date): string => {
|
||||
return format(date, "MMM d, yyyy");
|
||||
@@ -105,6 +138,13 @@ export function FeedPage() {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const isFocused = () => {
|
||||
const episodes = allEpisodes();
|
||||
const currentIndex = episodes.findIndex(
|
||||
(e: any) => e.episode.id === item.episode.id,
|
||||
);
|
||||
return currentIndex === focusedIndex();
|
||||
};
|
||||
return (
|
||||
<SelectableBox
|
||||
selected={isSelected}
|
||||
@@ -115,7 +155,11 @@ export function FeedPage() {
|
||||
paddingTop={0}
|
||||
paddingBottom={0}
|
||||
onMouseDown={() => {
|
||||
// Selection is handled by App's keyboard navigation
|
||||
setSelectedEpisodeID(item.episode.id);
|
||||
const episodes = allEpisodes();
|
||||
setFocusedIndex(
|
||||
episodes.findIndex((e: any) => e.episode.id === item.episode.id),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SelectableText selected={isSelected} primary>
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* Right panel: episodes for the selected show
|
||||
*/
|
||||
|
||||
import { createSignal, For, Show, createMemo, createEffect } from "solid-js";
|
||||
import { createSignal, For, Show, createMemo, createEffect, onMount } from "solid-js";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { useFeedStore } from "@/stores/feed";
|
||||
import { useDownloadStore } from "@/stores/download";
|
||||
import { DownloadStatus } from "@/types/episode";
|
||||
@@ -32,6 +33,50 @@ export function MyShowsPage() {
|
||||
const mutedColor = () => theme.muted || theme.text;
|
||||
const nav = useNavigation();
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isDown =
|
||||
keyEvent.key === "j" || keyEvent.key === "ArrowDown";
|
||||
const isUp =
|
||||
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
|
||||
const isSelect =
|
||||
keyEvent.key === "Enter" || keyEvent.key === " ";
|
||||
|
||||
const shows = feedStore.getFilteredFeeds();
|
||||
const episodesList = episodes();
|
||||
const selected = selectedShow();
|
||||
|
||||
if (isSelect) {
|
||||
if (shows.length > 0 && showIndex() < shows.length) {
|
||||
setShowIndex(showIndex() + 1);
|
||||
}
|
||||
if (episodesList.length > 0 && episodeIndex() < episodesList.length) {
|
||||
setEpisodeIndex(episodeIndex() + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (shows.length > 0) {
|
||||
if (isDown && showIndex() < shows.length - 1) {
|
||||
setShowIndex(showIndex() + 1);
|
||||
} else if (isUp && showIndex() > 0) {
|
||||
setShowIndex(showIndex() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (episodesList.length > 0) {
|
||||
if (isDown && episodeIndex() < episodesList.length - 1) {
|
||||
setEpisodeIndex(episodeIndex() + 1);
|
||||
} else if (isUp && episodeIndex() > 0) {
|
||||
setEpisodeIndex(episodeIndex() - 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
/** Threshold: load more when within this many items of the end */
|
||||
const LOAD_MORE_THRESHOLD = 5;
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { useAudio } from "@/hooks/useAudio";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { useNavigation } from "@/context/NavigationContext";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { onMount } from "solid-js";
|
||||
|
||||
enum PlayerPaneType {
|
||||
PLAYER = 1,
|
||||
@@ -15,6 +17,32 @@ export function PlayerPage() {
|
||||
const { theme } = useTheme();
|
||||
const nav = useNavigation();
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isNext = keyEvent.key === "l" || keyEvent.key === "ArrowRight";
|
||||
const isPrev = keyEvent.key === "h" || keyEvent.key === "ArrowLeft";
|
||||
const isPlayPause = keyEvent.key === " " || keyEvent.key === "Enter";
|
||||
|
||||
if (isPlayPause) {
|
||||
audio.togglePlayback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNext) {
|
||||
audio.seek(audio.currentEpisode()?.duration ?? 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPrev) {
|
||||
audio.seek(0);
|
||||
return;
|
||||
}
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
const progressPercent = () => {
|
||||
const d = audio.duration();
|
||||
if (d <= 0) return 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* SearchPage component - Main search interface for PodTUI
|
||||
*/
|
||||
|
||||
import { createSignal, createEffect, Show } from "solid-js";
|
||||
import { createSignal, createEffect, Show, onMount } from "solid-js";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { useSearchStore } from "@/stores/search";
|
||||
import { SearchResults } from "./SearchResults";
|
||||
@@ -27,6 +27,37 @@ export function SearchPage() {
|
||||
const { theme } = useTheme();
|
||||
const nav = useNavigation();
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isDown =
|
||||
keyEvent.key === "j" || keyEvent.key === "ArrowDown";
|
||||
const isUp =
|
||||
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
|
||||
const isSelect =
|
||||
keyEvent.key === "Enter" || keyEvent.key === " ";
|
||||
|
||||
if (isSelect) {
|
||||
const results = searchStore.results();
|
||||
if (results.length > 0 && resultIndex() < results.length) {
|
||||
setResultIndex(resultIndex() + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const results = searchStore.results();
|
||||
if (results.length === 0) return;
|
||||
|
||||
if (isDown && resultIndex() < results.length - 1) {
|
||||
setResultIndex(resultIndex() + 1);
|
||||
} else if (isUp && resultIndex() > 0) {
|
||||
setResultIndex(resultIndex() - 1);
|
||||
}
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
const handleSearch = async () => {
|
||||
const query = inputValue().trim();
|
||||
if (query) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createSignal, For } from "solid-js";
|
||||
import { createSignal, For, onMount } from "solid-js";
|
||||
import { useKeyboard } from "@opentui/solid";
|
||||
import { SourceManager } from "./SourceManager";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
@@ -33,6 +33,31 @@ export function SettingsPage() {
|
||||
return nav.activeDepth() === depth;
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
useKeyboard(
|
||||
(keyEvent: any) => {
|
||||
const isDown =
|
||||
keyEvent.key === "j" || keyEvent.key === "ArrowDown";
|
||||
const isUp =
|
||||
keyEvent.key === "k" || keyEvent.key === "ArrowUp";
|
||||
const isSelect =
|
||||
keyEvent.key === "Enter" || keyEvent.key === " ";
|
||||
|
||||
if (isSelect) {
|
||||
nav.setActiveDepth((nav.activeDepth() % SettingsPaneCount) + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
const nextDepth = isDown
|
||||
? (nav.activeDepth() % SettingsPaneCount) + 1
|
||||
: (nav.activeDepth() - 2 + SettingsPaneCount) % SettingsPaneCount + 1;
|
||||
|
||||
nav.setActiveDepth(nextDepth);
|
||||
},
|
||||
{ release: false },
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<box flexDirection="column" gap={1} height="100%" width="100%">
|
||||
<box flexDirection="row" gap={1}>
|
||||
|
||||
Reference in New Issue
Block a user