mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
Merge pull request #367 from AdityasahuX07/patch-17
[Updated]Added double tap on search button to open keyboard for ready to search feature.
This commit is contained in:
commit
f779febc32
2 changed files with 85 additions and 18 deletions
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useRef, useMemo, useState } from 'react';
|
||||||
import { NavigationContainer, DefaultTheme as NavigationDefaultTheme, DarkTheme as NavigationDarkTheme, Theme, NavigationProp } from '@react-navigation/native';
|
import { NavigationContainer, DefaultTheme as NavigationDefaultTheme, DarkTheme as NavigationDarkTheme, Theme, NavigationProp } from '@react-navigation/native';
|
||||||
import { createNativeStackNavigator, NativeStackNavigationOptions, NativeStackNavigationProp } from '@react-navigation/native-stack';
|
import { createNativeStackNavigator, NativeStackNavigationOptions, NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
import { createBottomTabNavigator, BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
|
import { createBottomTabNavigator, BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
|
||||||
import { useColorScheme, Platform, Animated, StatusBar, TouchableOpacity, View, Text, AppState, Easing, Dimensions } from 'react-native';
|
import { useColorScheme, Platform, Animated, StatusBar, TouchableOpacity, View, Text, AppState, Easing, Dimensions, DeviceEventEmitter } from 'react-native';
|
||||||
import { mmkvStorage } from '../services/mmkvStorage';
|
import { mmkvStorage } from '../services/mmkvStorage';
|
||||||
import { PaperProvider, MD3DarkTheme, MD3LightTheme, adaptNavigationTheme } from 'react-native-paper';
|
import { PaperProvider, MD3DarkTheme, MD3LightTheme, adaptNavigationTheme } from 'react-native-paper';
|
||||||
import type { MD3Theme } from 'react-native-paper';
|
import type { MD3Theme } from 'react-native-paper';
|
||||||
|
|
@ -473,7 +473,6 @@ const TabIcon = React.memo(({ focused, color, iconName, iconLibrary = 'material'
|
||||||
|
|
||||||
// Update the TabScreenWrapper component with fixed layout dimensions
|
// Update the TabScreenWrapper component with fixed layout dimensions
|
||||||
const TabScreenWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
const TabScreenWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||||
const [dimensions, setDimensions] = useState(Dimensions.get('window'));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const subscription = Dimensions.addEventListener('change', ({ window }) => {
|
const subscription = Dimensions.addEventListener('change', ({ window }) => {
|
||||||
|
|
@ -555,6 +554,7 @@ const MainTabs = () => {
|
||||||
const { settings: appSettings } = useSettingsHook();
|
const { settings: appSettings } = useSettingsHook();
|
||||||
const [hasUpdateBadge, setHasUpdateBadge] = React.useState(false);
|
const [hasUpdateBadge, setHasUpdateBadge] = React.useState(false);
|
||||||
const [dimensions, setDimensions] = useState(Dimensions.get('window'));
|
const [dimensions, setDimensions] = useState(Dimensions.get('window'));
|
||||||
|
const lastTapRef = useRef<Record<string, number>>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const subscription = Dimensions.addEventListener('change', ({ window }) => {
|
const subscription = Dimensions.addEventListener('change', ({ window }) => {
|
||||||
|
|
@ -692,15 +692,31 @@ const MainTabs = () => {
|
||||||
|
|
||||||
const isFocused = props.state.index === index;
|
const isFocused = props.state.index === index;
|
||||||
|
|
||||||
|
const lastTapRef = useRef<Record<string, number>>({}); // Add this ref at the top of MainTabs component
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
|
const now = Date.now();
|
||||||
|
const DOUBLE_TAP_DELAY = 300;
|
||||||
|
const lastTap = lastTapRef.current[route.name] || 0;
|
||||||
|
const isSearchDoubleTap = route.name === 'Search' && (now - lastTap) < DOUBLE_TAP_DELAY;
|
||||||
|
|
||||||
|
// Update last tap time
|
||||||
|
lastTapRef.current[route.name] = now;
|
||||||
|
|
||||||
const event = props.navigation.emit({
|
const event = props.navigation.emit({
|
||||||
type: 'tabPress',
|
type: 'tabPress',
|
||||||
target: route.key,
|
target: route.key,
|
||||||
canPreventDefault: true,
|
canPreventDefault: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isFocused) {
|
if (isFocused) {
|
||||||
// Same tab pressed - emit scroll to top
|
// If double tap on Search -> Open Keyboard
|
||||||
emitScrollToTop(route.name);
|
if (isSearchDoubleTap) {
|
||||||
|
DeviceEventEmitter.emit('FOCUS_SEARCH_INPUT');
|
||||||
|
} else {
|
||||||
|
// Single tap on active tab -> Scroll to Top
|
||||||
|
emitScrollToTop(route.name);
|
||||||
|
}
|
||||||
} else if (!event.defaultPrevented) {
|
} else if (!event.defaultPrevented) {
|
||||||
props.navigation.navigate(route.name);
|
props.navigation.navigate(route.name);
|
||||||
}
|
}
|
||||||
|
|
@ -810,19 +826,29 @@ const MainTabs = () => {
|
||||||
const isFocused = props.state.index === index;
|
const isFocused = props.state.index === index;
|
||||||
|
|
||||||
const onPress = () => {
|
const onPress = () => {
|
||||||
const event = props.navigation.emit({
|
const now = Date.now();
|
||||||
type: 'tabPress',
|
const DOUBLE_TAP_DELAY = 300;
|
||||||
target: route.key,
|
const lastTap = lastTapRef.current[route.name] || 0;
|
||||||
canPreventDefault: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isFocused) {
|
// DOUBLE TAP LOGIC: If search is pressed twice quickly
|
||||||
// Same tab pressed - emit scroll to top
|
if (route.name === 'Search' && now - lastTap < DOUBLE_TAP_DELAY) {
|
||||||
emitScrollToTop(route.name);
|
DeviceEventEmitter.emit('FOCUS_SEARCH_INPUT');
|
||||||
} else if (!event.defaultPrevented) {
|
}
|
||||||
props.navigation.navigate(route.name);
|
|
||||||
}
|
lastTapRef.current[route.name] = now;
|
||||||
};
|
|
||||||
|
const event = props.navigation.emit({
|
||||||
|
type: 'tabPress',
|
||||||
|
target: route.key,
|
||||||
|
canPreventDefault: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isFocused) {
|
||||||
|
emitScrollToTop(route.name);
|
||||||
|
} else if (!event.defaultPrevented) {
|
||||||
|
props.navigation.navigate(route.name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let iconName: IconNameType = 'home';
|
let iconName: IconNameType = 'home';
|
||||||
let iconLibrary: 'material' | 'feather' | 'ionicons' = 'material';
|
let iconLibrary: 'material' | 'feather' | 'ionicons' = 'material';
|
||||||
|
|
@ -1080,8 +1106,29 @@ const MainTabs = () => {
|
||||||
options={{
|
options={{
|
||||||
tabBarLabel: t('navigation.search'),
|
tabBarLabel: t('navigation.search'),
|
||||||
tabBarIcon: ({ color, size }) => (
|
tabBarIcon: ({ color, size }) => (
|
||||||
<MaterialCommunityIcons name={'magnify'} size={size} color={color} />
|
<Feather name="search" size={size} color={color} />
|
||||||
),
|
),
|
||||||
|
tabBarButton: (props) => {
|
||||||
|
const lastTap = useRef(0);
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
{...props}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
onPress={(e) => {
|
||||||
|
const now = Date.now();
|
||||||
|
const DOUBLE_TAP_DELAY = 300;
|
||||||
|
|
||||||
|
// Check for double tap
|
||||||
|
if (now - lastTap.current < DOUBLE_TAP_DELAY) {
|
||||||
|
DeviceEventEmitter.emit('FOCUS_SEARCH_INPUT');
|
||||||
|
} else {
|
||||||
|
props.onPress?.(e);
|
||||||
|
}
|
||||||
|
lastTap.current = now;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{appSettings?.enableDownloads !== false && (
|
{appSettings?.enableDownloads !== false && (
|
||||||
|
|
@ -1790,4 +1837,4 @@ const AppNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootStack
|
||||||
</PostHogProvider>
|
</PostHogProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default AppNavigator;
|
export default AppNavigator;
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,26 @@ const SearchScreen = () => {
|
||||||
return () => { isMounted.current = false; };
|
return () => { isMounted.current = false; };
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const focusSubscription = DeviceEventEmitter.addListener('FOCUS_SEARCH_INPUT', () => {
|
||||||
|
// Optional: Reset search state if user double taps while on search
|
||||||
|
if (query.length === 0) {
|
||||||
|
setResults({ byAddon: [], allResults: [] });
|
||||||
|
setSearched(false);
|
||||||
|
setShowRecent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a small timeout to ensure the UI is ready
|
||||||
|
setTimeout(() => {
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
}, 120);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => focusSubscription.remove();
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
// Update isSaved and isWatched when selectedItem changes
|
// Update isSaved and isWatched when selectedItem changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedItem) return;
|
if (!selectedItem) return;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue