mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-13 07:52:59 +01:00
feat: focus search bar on second tab press (#558)
This commit is contained in:
committed by
GitHub
parent
5590c2f784
commit
af2bd030e9
@@ -26,12 +26,14 @@ import React, {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useLayoutEffect,
|
useLayoutEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { Platform, ScrollView, TouchableOpacity, View } from "react-native";
|
import { Platform, ScrollView, TouchableOpacity, View } from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import { useDebounce } from "use-debounce";
|
import { useDebounce } from "use-debounce";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { eventBus } from "@/utils/eventBus";
|
||||||
|
|
||||||
type SearchType = "Library" | "Discover";
|
type SearchType = "Library" | "Discover";
|
||||||
|
|
||||||
@@ -120,21 +122,44 @@ export default function search() {
|
|||||||
[api, searchEngine, settings]
|
[api, searchEngine, settings]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
type HeaderSearchBarRef = {
|
||||||
|
focus: () => void;
|
||||||
|
blur: () => void;
|
||||||
|
setText: (text: string) => void;
|
||||||
|
clearText: () => void;
|
||||||
|
cancelSearch: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchBarRef = useRef<HeaderSearchBarRef>(null);
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerSearchBarOptions: {
|
headerSearchBarOptions: {
|
||||||
|
ref: searchBarRef,
|
||||||
placeholder: t("search.search"),
|
placeholder: t("search.search"),
|
||||||
onChangeText: (e: any) => {
|
onChangeText: (e: any) => {
|
||||||
router.setParams({ q: "" });
|
router.setParams({ q: "" });
|
||||||
setSearch(e.nativeEvent.text);
|
setSearch(e.nativeEvent.text);
|
||||||
},
|
},
|
||||||
hideWhenScrolling: false,
|
hideWhenScrolling: false,
|
||||||
autoFocus: true,
|
autoFocus: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, [navigation]);
|
}, [navigation]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = eventBus.on("searchTabPressed", () => {
|
||||||
|
// Screen not actuve
|
||||||
|
if (!searchBarRef.current) return;
|
||||||
|
// Screen is active, focus search bar
|
||||||
|
searchBarRef.current?.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const { data: movies, isFetching: l1 } = useQuery({
|
const { data: movies, isFetching: l1 } = useQuery({
|
||||||
queryKey: ["search", "movies", debouncedSearch],
|
queryKey: ["search", "movies", debouncedSearch],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import type {
|
|||||||
TabNavigationState,
|
TabNavigationState,
|
||||||
} from "@react-navigation/native";
|
} from "@react-navigation/native";
|
||||||
import { SystemBars } from "react-native-edge-to-edge";
|
import { SystemBars } from "react-native-edge-to-edge";
|
||||||
|
import { eventBus } from "@/utils/eventBus";
|
||||||
|
|
||||||
export const NativeTabs = withLayoutContext<
|
export const NativeTabs = withLayoutContext<
|
||||||
BottomTabNavigationOptions,
|
BottomTabNavigationOptions,
|
||||||
@@ -76,6 +77,11 @@ export default function TabLayout() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<NativeTabs.Screen
|
<NativeTabs.Screen
|
||||||
|
listeners={({ navigation }) => ({
|
||||||
|
tabPress: (e) => {
|
||||||
|
eventBus.emit("searchTabPressed");
|
||||||
|
},
|
||||||
|
})}
|
||||||
name="(search)"
|
name="(search)"
|
||||||
options={{
|
options={{
|
||||||
title: t("tabs.search"),
|
title: t("tabs.search"),
|
||||||
@@ -137,4 +143,4 @@ export default function TabLayout() {
|
|||||||
</NativeTabs>
|
</NativeTabs>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
26
utils/eventBus.ts
Normal file
26
utils/eventBus.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
type Listener<T = void> = (data?: T) => void;
|
||||||
|
|
||||||
|
class EventBus {
|
||||||
|
private listeners: Record<string, Listener<any>[]> = {};
|
||||||
|
|
||||||
|
on<T = void>(event: string, callback: Listener<T>): () => void {
|
||||||
|
if (!this.listeners[event]) {
|
||||||
|
this.listeners[event] = [];
|
||||||
|
}
|
||||||
|
this.listeners[event].push(callback);
|
||||||
|
return () => this.off(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
off<T = void>(event: string, callback: Listener<T>): void {
|
||||||
|
if (!this.listeners[event]) return;
|
||||||
|
this.listeners[event] = this.listeners[event].filter(
|
||||||
|
(fn) => fn !== callback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit<T = void>(event: string, data?: T): void {
|
||||||
|
this.listeners[event]?.forEach((callback) => callback(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const eventBus = new EventBus();
|
||||||
Reference in New Issue
Block a user