Skip to content

Commit d58daf5

Browse files
authored
Merge pull request #24 from RonasIT/PRD-2110-Android-layout-fix
PRD-2110: Edge-to-edge, 3-button-navigation bar bottom paddings fix
2 parents 60638ca + 867e64f commit d58daf5

18 files changed

Lines changed: 157 additions & 45 deletions

File tree

apps/mobile/app/(main)/chat/[id].tsx

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
AppText,
1111
Icon,
1212
FullScreenSearchModal,
13+
AppKeyboardControllerView,
1314
} from '@open-webui-react-native/mobile/shared/ui/ui-kit';
1415
import { ChatScreenParams, useInitialNavigation } from '@open-webui-react-native/mobile/shared/utils/navigation';
1516
import { modelsApi } from '@open-webui-react-native/shared/data-access/api';
@@ -48,34 +49,36 @@ export default function ChatScreen(): ReactElement {
4849
);
4950

5051
return (
51-
<AppScreen
52-
className={cn(isOfflineMode && 'pt-20')}
53-
noOutsideSpacing
54-
header={
55-
<AppHeader
56-
title={
57-
modelId || isLoading ? (
58-
<FullScreenSearchModal
59-
data={models || []}
60-
renderTrigger={renderTrigger}
61-
selectedItemId={modelId}
62-
onSelectItem={onSelectModel}
63-
searchPlaceholder={translate('TEXT_SELECT_A_MODEL')}
64-
/>
65-
) : (
66-
translate('TEXT_LOADING')
67-
)
68-
}
69-
onGoBack={handleGoBackPress}
70-
/>
71-
}
72-
scrollDisabled>
73-
<NoConnectionBanner isVisible={isOfflineMode} />
74-
<Chat
75-
chatId={id}
76-
isNewChat={!!isNewChat}
77-
selectedModelId={modelId}
78-
resetToChatsList={handleResetToChatsList} />
79-
</AppScreen>
52+
<AppKeyboardControllerView className='bg-background-primary'>
53+
<AppScreen
54+
className={cn(isOfflineMode && 'pt-20')}
55+
noOutsideSpacing
56+
header={
57+
<AppHeader
58+
title={
59+
modelId || isLoading ? (
60+
<FullScreenSearchModal
61+
data={models || []}
62+
renderTrigger={renderTrigger}
63+
selectedItemId={modelId}
64+
onSelectItem={onSelectModel}
65+
searchPlaceholder={translate('TEXT_SELECT_A_MODEL')}
66+
/>
67+
) : (
68+
translate('TEXT_LOADING')
69+
)
70+
}
71+
onGoBack={handleGoBackPress}
72+
/>
73+
}
74+
scrollDisabled>
75+
<NoConnectionBanner isVisible={isOfflineMode} />
76+
<Chat
77+
chatId={id}
78+
isNewChat={!!isNewChat}
79+
selectedModelId={modelId}
80+
resetToChatsList={handleResetToChatsList} />
81+
</AppScreen>
82+
</AppKeyboardControllerView>
8083
);
8184
}

apps/mobile/app/_layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function App(): ReactElement | null {
7373

7474
return (
7575
<View className='bg-background-primary flex-1'>
76-
<StatusBar className='bg-background-primary' />
76+
<StatusBar className='bg-background-primary' translucent />
7777
<Stack>
7878
<Stack.Screen name='index' options={{ headerShown: false, contentStyle: { backgroundColor: 'transparent' } }} />
7979
<Stack.Screen name={navigationConfig.auth.root} options={{ headerShown: false }} />

libs/mobile/chat/features/archived-chats-list/src/lib/component.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
PressableSearchInput,
1818
View,
1919
} from '@open-webui-react-native/mobile/shared/ui/ui-kit';
20+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
2021
import { chatApi, ChatListItem } from '@open-webui-react-native/shared/data-access/api';
2122
import { formatDateTime } from '@open-webui-react-native/shared/utils/date';
2223
import { ArchivedChatsActionsSheet } from './components';
@@ -33,6 +34,7 @@ export function ArchivedChatsList({
3334
onSearchPress,
3435
}: ArchivedChatsListProps): ReactElement {
3536
const translate = useTranslation('CHAT.ARCHIVED_CHATS_LIST');
37+
const bottomInset = useBottomInset();
3638

3739
const { filters, selectedFilter, handleFilterPress, resetFilter } = useSearchFilters();
3840

@@ -110,7 +112,7 @@ export function ArchivedChatsList({
110112
ListEmptyComponent={
111113
<ListEmptyComponent containerClassName='mt-16' description={translate('TEXT_NO_CHATS')} />
112114
}
113-
contentContainerClassName='pb-safe android:pb-16'
115+
contentContainerStyle={{ paddingBottom: bottomInset }}
114116
/>
115117
)}
116118
</View>

libs/mobile/chat/features/chat/src/lib/component.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { useSelector } from '@legendapp/state/react';
2+
import { useKeyboard } from '@react-native-community/hooks';
23
import { useTranslation } from '@ronas-it/react-native-common-modules/i18n';
34
import dayjs from 'dayjs';
45
import { delay } from 'lodash-es';
5-
import React, { ReactElement, useEffect, useState } from 'react';
6+
import React, { Fragment, ReactElement, useEffect, useState } from 'react';
67
import { useForm } from 'react-hook-form';
78
import { InteractionManager } from 'react-native';
89
import { EditMessageInput } from '@open-webui-react-native/mobile/chat/features/edit-message-input';
@@ -11,8 +12,9 @@ import { useEditMessage } from '@open-webui-react-native/mobile/chat/features/us
1112
import { useSendMessage } from '@open-webui-react-native/mobile/chat/features/use-send-message';
1213
import { useAttachedFiles } from '@open-webui-react-native/mobile/shared/features/use-attached-files';
1314
import { cn } from '@open-webui-react-native/mobile/shared/ui/styles';
14-
import { AppKeyboardControllerView, AppSpinner, View } from '@open-webui-react-native/mobile/shared/ui/ui-kit';
15+
import { AppSpinner, View } from '@open-webui-react-native/mobile/shared/ui/ui-kit';
1516
import { FormValues } from '@open-webui-react-native/mobile/shared/utils/form';
17+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
1618
import { chatApi, ChatGenerationOption, chatQueriesKeys } from '@open-webui-react-native/shared/data-access/api';
1719
import { Role } from '@open-webui-react-native/shared/data-access/common';
1820
import { useSubscribeToQueryCache } from '@open-webui-react-native/shared/data-access/query-client';
@@ -32,6 +34,8 @@ interface ChatProps {
3234

3335
export function Chat({ chatId, selectedModelId, isNewChat, resetToChatsList }: ChatProps): ReactElement {
3436
const translate = useTranslation('CHAT.CHAT');
37+
const bottomInset = useBottomInset();
38+
const { keyboardShown } = useKeyboard();
3539

3640
const [isInputFocusing, setIsInputFocusing] = useState(false); //NOTE: Needs to avoid ChatBottomButton jumping when auto-scrolling after focus
3741

@@ -126,7 +130,7 @@ export function Chat({ chatId, selectedModelId, isNewChat, resetToChatsList }: C
126130
}, [isNewChat, isSuccess, chatId]);
127131

128132
return (
129-
<AppKeyboardControllerView>
133+
<Fragment>
130134
{shouldHideContent && (
131135
<View className='absolute w-full h-full z-50 bg-background-primary items-center justify-center'>
132136
<AppSpinner />
@@ -148,7 +152,9 @@ export function Chat({ chatId, selectedModelId, isNewChat, resetToChatsList }: C
148152
/>
149153
</React.Suspense>
150154
)}
151-
<View className={cn('pb-safe android:pb-16 pt-8 px-16', shouldHideContent && 'opacity-0')}>
155+
<View
156+
style={!keyboardShown && { paddingBottom: bottomInset }}
157+
className={cn('pt-8 px-16', shouldHideContent && 'opacity-0')}>
152158
{editingMessageId ? (
153159
<EditMessageInput
154160
control={editMessageControl}
@@ -179,6 +185,6 @@ export function Chat({ chatId, selectedModelId, isNewChat, resetToChatsList }: C
179185
/>
180186
)}
181187
</View>
182-
</AppKeyboardControllerView>
188+
</Fragment>
183189
);
184190
}

libs/mobile/chat/features/menu-list/src/lib/component.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
PressableSearchInput,
1414
View,
1515
} from '@open-webui-react-native/mobile/shared/ui/ui-kit';
16+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
1617
import { chatApi, ChatListItem, FolderListItem, foldersApi } from '@open-webui-react-native/shared/data-access/api';
1718
import { formatDateTime } from '@open-webui-react-native/shared/utils/date';
1819
import { FeatureID, isFeatureEnabled } from '@open-webui-react-native/shared/utils/feature-flag';
@@ -37,6 +38,7 @@ export function ChatMenuList({
3738
}: ChatMenuListProps): ReactElement {
3839
const translate = useTranslation('CHAT.CHAT_MENU_LIST');
3940
const chatActionsSheetRef = useRef<ChatActionsMenuSheetMethods>(null);
41+
const bottomInset = useBottomInset();
4042

4143
const [isFirstLoading, setIsFirstLoading] = useState<boolean>(true);
4244

@@ -119,7 +121,8 @@ export function ChatMenuList({
119121
/>
120122
}
121123
ListFooterComponent={isFetchingNextPage ? <AppSpinner /> : null}
122-
contentContainerClassName='mt-12 pb-safe android:pb-24'
124+
contentContainerClassName='mt-12'
125+
contentContainerStyle={{ paddingBottom: bottomInset }}
123126
showsVerticalScrollIndicator={false}
124127
/>
125128
)}

libs/mobile/chat/features/search-archived-chats/src/lib/component.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
SearchInput,
1818
View,
1919
} from '@open-webui-react-native/mobile/shared/ui/ui-kit';
20+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
2021
import { chatApi, ChatListItem } from '@open-webui-react-native/shared/data-access/api';
2122
import { formatDateTime } from '@open-webui-react-native/shared/utils/date';
2223
import { useDebouncedQuery } from '@open-webui-react-native/shared/utils/use-debounced-query';
@@ -28,6 +29,7 @@ interface SearchArchivedChatsProps {
2829

2930
export function SearchArchivedChats({ onArchivedChatPress, onGoBack }: SearchArchivedChatsProps): ReactElement {
3031
const translate = useTranslation('CHAT.ARCHIVED_CHATS_LIST');
32+
const bottomInset = useBottomInset();
3133

3234
const { filters, selectedFilter, handleFilterPress } = useSearchFilters();
3335

@@ -85,7 +87,7 @@ export function SearchArchivedChats({ onArchivedChatPress, onGoBack }: SearchArc
8587
{isLoading ? <AppSpinner /> : <ListEmptyComponent description={translate('TEXT_NO_CHATS')} />}
8688
</View>
8789
}
88-
contentContainerClassName='pb-safe android:pb-16'
90+
contentContainerStyle={{ paddingBottom: bottomInset }}
8991
/>
9092
</AnimatedView>
9193
)}

libs/mobile/shared/ui/ui-kit/src/bottom-sheet/component.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
2828
import { SetOptional } from 'type-fest';
2929
import { cn, screenHeight } from '@open-webui-react-native/mobile/shared/ui/styles';
3030
import { uiState$ } from '@open-webui-react-native/mobile/shared/ui/ui-state';
31+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
3132
import { View } from '../view';
3233

3334
type NativeWindProps = {
@@ -94,7 +95,8 @@ export function AppBottomSheet({
9495
...restProps
9596
}: AppBottomSheetPropsType): ReactElement {
9697
const { top } = useSafeAreaInsets();
97-
const { keyboardHeight, keyboardShown } = useKeyboard();
98+
const bottomInset = useBottomInset();
99+
const { keyboardShown } = useKeyboard();
98100
const elementRef = useRef<BottomSheetModal>(null);
99101
const [isSheetOpen, setIsSheetOpen] = useState<boolean>(false);
100102

@@ -132,9 +134,7 @@ export function AppBottomSheet({
132134
<View className='flex-1 px-content-offset pt-content-offset'>{content}</View>
133135
) : (
134136
<BottomSheetView>
135-
<View
136-
className='px-content-offset pt-content-offset pb-safe android:pb-16'
137-
style={keyboardShown && !withoutKeyboardExtraPadding ? { paddingBottom: keyboardHeight } : undefined}>
137+
<View className='px-content-offset pt-content-offset' style={{ paddingBottom: bottomInset }}>
138138
{content}
139139
</View>
140140
</BottomSheetView>

libs/mobile/shared/ui/ui-kit/src/full-screen-search-modal/component.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import React, {
1313
} from 'react';
1414
import { InteractionManager } from 'react-native';
1515
import { FadeIn } from 'react-native-reanimated';
16+
import { useBottomInset } from '@open-webui-react-native/mobile/shared/utils/use-bottom-inset';
1617
// eslint-disable-next-line @nx/enforce-module-boundaries
1718
import { MockFolderItemIds } from '@open-webui-react-native/shared/data-access/api';
1819
import { useDebouncedQuery } from '@open-webui-react-native/shared/utils/use-debounced-query';
@@ -53,6 +54,7 @@ export function FullScreenSearchModal<Item extends FullScreenSearchListItem>({
5354
ref,
5455
}: FullScreenSearchModalProps<Item>): ReactElement {
5556
const listRef = useRef<React.ComponentRef<typeof FlashList<Item>>>(null);
57+
const bottomInset = useBottomInset();
5658

5759
const [isOpen, setIsOpen] = useState<boolean>(false);
5860
const [isAnimationCompleted, setIsAnimationCompleted] = useState<boolean>(false);
@@ -153,7 +155,8 @@ export function FullScreenSearchModal<Item extends FullScreenSearchListItem>({
153155
<AppFlashList
154156
ref={listRef as Ref<React.ComponentRef<typeof FlashList<Item>>>}
155157
extraData={query}
156-
contentContainerClassName='pt-24 pb-safe android:pb-16'
158+
contentContainerClassName='pt-24'
159+
contentContainerStyle={{ paddingBottom: bottomInset }}
157160
showsVerticalScrollIndicator={false}
158161
keyboardShouldPersistTaps='handled'
159162
renderItem={renderItem}

libs/mobile/shared/ui/ui-kit/src/keyboard-controller-view/component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ export function AppKeyboardControllerView({
2222
}: AppKeyboardControllerViewProps): ReactElement {
2323
const { top } = useSafeAreaInsets();
2424
const verticalOffset = Platform.select({
25-
ios: isInBottomSheet ? top : top + 8,
26-
android: isInBottomSheet ? 85 : 32,
25+
ios: isInBottomSheet ? top : 16,
26+
android: isInBottomSheet ? 85 : 16,
2727
});
2828

2929
return (
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"presets": [
3+
[
4+
"@nx/react/babel",
5+
{
6+
"runtime": "automatic",
7+
"useBuiltIns": "usage"
8+
}
9+
]
10+
],
11+
"plugins": []
12+
}

0 commit comments

Comments
 (0)