Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions apps/expo/app/(app)/ai-chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
Dimensions,
type NativeSyntheticEvent,
Platform,
Pressable,
ScrollView,
TextInput,
type TextInputContentSizeChangeEventData,
Expand Down Expand Up @@ -402,6 +403,7 @@ function Composer({
}) {
const { colors, isDarkColorScheme } = useColorScheme();
const insets = useSafeAreaInsets();
const textInputRef = React.useRef<TextInput>(null);

function onContentSizeChange(event: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) {
textInputHeight.value = Math.max(
Expand All @@ -410,6 +412,14 @@ function Composer({
);
}

// On Android, manually focus the TextInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handlePressIn = React.useCallback(() => {
if (Platform.OS === 'android') {
textInputRef.current?.focus();
}
}, []);

return (
<BlurView
intensity={Platform.select({ ios: 50, default: 0 })}
Expand All @@ -425,16 +435,21 @@ function Composer({
]}
>
<View className="flex-row items-end gap-2 px-4 py-2">
<TextInput
placeholder={placeholder}
style={TEXT_INPUT_STYLE}
className="ios:pt-[7px] ios:pb-1 min-h-9 flex-1 rounded-[18px] border border-border bg-background py-1 pl-3 pr-8 text-base leading-5 text-foreground"
placeholderTextColor={colors.grey2}
multiline
onContentSizeChange={onContentSizeChange}
onChangeText={handleInputChange}
value={input}
/>
<Pressable onPressIn={handlePressIn} className="min-h-9 flex-1">
<TextInput
ref={textInputRef}
placeholder={placeholder}
style={TEXT_INPUT_STYLE}
className="ios:pt-[7px] ios:pb-1 min-h-9 flex-1 rounded-[18px] border border-border bg-background py-1 pl-3 pr-8 text-base leading-5 text-foreground"
placeholderTextColor={colors.grey2}
multiline
onContentSizeChange={onContentSizeChange}
onChangeText={handleInputChange}
value={input}
// Ensures the soft keyboard is shown when the input is focused (Android keyboard fix)
showSoftInputOnFocus
/>
</Pressable>
<View className="absolute bottom-3 right-5">
{isLoading ? (
<Button onPress={stop} size="icon" variant="primary" className="h-7 w-7 rounded-full">
Expand Down
26 changes: 22 additions & 4 deletions apps/expo/app/(app)/trip/location-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { ActivityIndicator, Button, SearchInput } from '@packrat/ui/nativewindui
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import Constants from 'expo-constants';
import { useRouter } from 'expo-router';
import { useRef, useState } from 'react';
import { Alert, Text, View } from 'react-native';
import { useEffect, useRef, useState } from 'react';
import { Alert, Platform, Pressable, Text, type TextInput, View } from 'react-native';
import MapView, { Marker, PROVIDER_GOOGLE } from 'react-native-maps';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useTripLocation } from '../../../features/trips/store/tripLocationStore';

export default function LocationSearchScreen() {
const router = useRouter();
const mapRef = useRef<MapView>(null);
const searchInputRef = useRef<TextInput>(null);
const { setLocation } = useTripLocation();
const { t } = useTranslation();

Expand All @@ -22,6 +23,22 @@ export default function LocationSearchScreen() {
} | null>(null);
const [isLoading, setIsLoading] = useState(false);

// Focus search input on mount with a delay to ensure the screen transition is complete
// and the input is ready to receive focus
useEffect(() => {
setTimeout(() => {
searchInputRef.current?.focus();
}, 300);
}, []);

// On Android, manually focus the SearchInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handleSearchInputPressIn = () => {
if (Platform.OS === 'android') {
searchInputRef.current?.focus();
}
};

const GOOGLE_MAPS_API_KEY =
Constants.expoConfig?.extra?.googleMapsApiKey || process.env.EXPO_PUBLIC_GOOGLE_MAPS_API_KEY;

Expand Down Expand Up @@ -90,14 +107,15 @@ export default function LocationSearchScreen() {
return (
<SafeAreaView className="flex-1 bg-background">
<View className="p-4 border-b border-border bg-background flex-row items-center space-x-2">
<View className="flex-1">
<Pressable className="flex-1" onPressIn={handleSearchInputPressIn}>
<SearchInput
ref={searchInputRef}
placeholder={t('location.searchForPlace')}
value={searchQuery}
onChangeText={setSearchQuery}
onSubmitEditing={handleSearch}
/>
</View>
</Pressable>
<Button onPress={handleSearch} variant="secondary" size="sm">
<Text className="text-foreground font-medium">{t('location.searchButton')}</Text>
</Button>
Expand Down
31 changes: 23 additions & 8 deletions apps/expo/features/catalog/components/CatalogBrowserModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { HorizontalCatalogItemCard } from 'expo-app/features/packs/components/Ho
import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { useAtom } from 'jotai';
import { useMemo, useState } from 'react';
import { useCallback, useMemo, useRef, useState } from 'react';
import {
ActivityIndicator,
FlatList,
Modal,
Platform,
Pressable,
RefreshControl,
type TextInput,
TouchableOpacity,
View,
} from 'react-native';
Expand Down Expand Up @@ -39,6 +42,15 @@ export function CatalogBrowserModal({
const [activeFilter, setActiveFilter] = useState<'All' | string>('All');
const [selectedItems, setSelectedItems] = useState<Set<number>>(new Set());
const [debouncedSearchValue] = useDebounce(searchValue, 400);
const searchInputRef = useRef<TextInput>(null);

// On Android, manually focus the SearchInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handleSearchInputPressIn = useCallback(() => {
if (Platform.OS === 'android') {
searchInputRef.current?.focus();
}
}, []);

const isSearching = debouncedSearchValue.length > 0;

Expand Down Expand Up @@ -134,13 +146,16 @@ export function CatalogBrowserModal({

{/* Search and Filter */}
<View className="p-4">
<SearchInput
textContentType="none"
autoComplete="off"
value={searchValue}
onChangeText={setSearchValue}
placeholder={t('catalog.searchEllipsis')}
/>
<Pressable onPressIn={handleSearchInputPressIn}>
<SearchInput
ref={searchInputRef}
textContentType="none"
autoComplete="off"
value={searchValue}
onChangeText={setSearchValue}
placeholder={t('catalog.searchEllipsis')}
/>
</Pressable>

{!isSearching && categories && (
<View className="mt-3">
Expand Down
25 changes: 21 additions & 4 deletions apps/expo/features/catalog/screens/PackSelectionScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ import { useDetailedPacks } from 'expo-app/features/packs';
import { useColorScheme } from 'expo-app/lib/hooks/useColorScheme';
import { useTranslation } from 'expo-app/lib/hooks/useTranslation';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { useMemo, useState } from 'react';
import { FlatList, TouchableOpacity, View } from 'react-native';
import { useCallback, useMemo, useRef, useState } from 'react';
import {
FlatList,
Platform,
Pressable,
type TextInput,
TouchableOpacity,
View,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { CatalogItemImage } from '../components/CatalogItemImage';
import { useCatalogItemDetails } from '../hooks';
Expand All @@ -18,6 +25,15 @@ export function PackSelectionScreen() {
const [searchQuery, setSearchQuery] = useState('');
const { colors } = useColorScheme();
const { t } = useTranslation();
const searchInputRef = useRef<TextInput>(null);

// On Android, manually focus the SearchInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handleSearchInputPressIn = useCallback(() => {
if (Platform.OS === 'android') {
searchInputRef.current?.focus();
}
}, []);

const filteredPacks = useMemo(() => {
if (!packs) return [];
Expand Down Expand Up @@ -79,14 +95,15 @@ export function PackSelectionScreen() {
)}

<View className="p-4">
<View className="mb-4">
<Pressable className="mb-4" onPressIn={handleSearchInputPressIn}>
<SearchInput
ref={searchInputRef}
textContentType="none"
autoComplete="off"
value={searchQuery}
onChangeText={setSearchQuery}
/>
</View>
</Pressable>

{filteredPacks && filteredPacks.length > 0 ? (
<>
Expand Down
18 changes: 14 additions & 4 deletions apps/expo/features/weather/screens/LocationSearchScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SearchInput, type SearchInputRef, Text } from '@packrat/ui/nativewindui';
import { SearchInput, Text } from '@packrat/ui/nativewindui';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Icon } from '@roninoss/icons';
import { cn } from 'expo-app/lib/cn';
Expand All @@ -15,6 +15,8 @@ import {
Keyboard,
Linking,
Platform,
Pressable,
type TextInput,
TouchableOpacity,
View,
} from 'react-native';
Expand All @@ -32,13 +34,21 @@ export default function LocationSearchScreen() {
const [query, setQuery] = useState('');
const { isLoading, results, error, search, addSearchResult, searchByCoordinates } =
useLocationSearch();
const searchInputRef = useRef<SearchInputRef>(null);
const searchInputRef = useRef<TextInput>(null);
const [recentSearches, setRecentSearches] = useState<string[]>([]);
const [isAdding, setIsAdding] = useState(false);
const [addingLocationId, setAddingLocationId] = useState<number | null>(null);
const [isGettingLocation, setIsGettingLocation] = useState(false);
const [locationPermissionDenied, setLocationPermissionDenied] = useState(false);

// On Android, manually focus the SearchInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handleSearchInputPressIn = () => {
if (Platform.OS === 'android') {
searchInputRef.current?.focus();
}
};

// Focus search input on mount
useEffect(() => {
setTimeout(() => {
Expand Down Expand Up @@ -389,7 +399,7 @@ export default function LocationSearchScreen() {
return (
<SafeAreaView className="flex-1 bg-background">
{/* Search Input */}
<View className="px-4">
<Pressable className="px-4" onPressIn={handleSearchInputPressIn}>
<SearchInput
ref={searchInputRef}
placeholder={t('weather.searchForCity')}
Expand All @@ -399,7 +409,7 @@ export default function LocationSearchScreen() {
autoFocus
clearButtonMode="while-editing"
/>
</View>
</Pressable>

{/* Results List */}
{isLoading && query.length > 0 ? (
Expand Down
16 changes: 13 additions & 3 deletions apps/expo/features/weather/screens/LocationsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import {
ActivityIndicator,
Alert,
Keyboard,
Platform,
Pressable,
RefreshControl,
ScrollView,
type TextInput,
TouchableOpacity,
View,
} from 'react-native';
Expand All @@ -34,9 +36,17 @@ function LocationsScreen() {
const { setActiveLocation } = useActiveLocation();
const { isRefreshing, refreshAllLocations } = useLocationRefresh();
const [isSearchFocused, setIsSearchFocused] = useState(false);
const searchInputRef = useRef(null);
const searchInputRef = useRef<TextInput>(null);
const { removeLocation } = useLocations();

// On Android, manually focus the SearchInput when the area is pressed.
// This fixes an issue where the keyboard doesn't reappear after being dismissed.
const handleSearchInputPressIn = useCallback(() => {
if (Platform.OS === 'android') {
searchInputRef.current?.focus();
}
}, []);

// Determine if we're loading
const isLoading = locationsState.state === 'loading';

Expand Down Expand Up @@ -133,7 +143,7 @@ function LocationsScreen() {
)}
/>

<View className="p-4">
<Pressable className="p-4" onPressIn={handleSearchInputPressIn}>
<SearchInput
ref={searchInputRef}
placeholder={t('weather.searchSavedLocations')}
Expand All @@ -148,7 +158,7 @@ function LocationsScreen() {
}
}}
/>
</View>
</Pressable>

{showNoSearchResults && (
<Animated.View
Expand Down
Loading