Skip to content

Commit 916a3df

Browse files
authored
Merge pull request #174 from Resgrid/develop
CU-868frp6xf Fixing onboarding, toast and new call creation.
2 parents de4a0ee + 1b15143 commit 916a3df

File tree

15 files changed

+344
-289
lines changed

15 files changed

+344
-289
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Android Tablet Safe Area Handling Fix
2+
3+
## Problem
4+
On Android tablets, the new call view did not hide or properly handle the bottom Android system navigation bar, causing it to overlap with the bottom buttons of the form.
5+
6+
## Root Cause
7+
The new call screen was not using proper safe area handling for Android devices, specifically:
8+
1. Missing `FocusAwareStatusBar` component for edge-to-edge experience
9+
2. No safe area insets applied to prevent overlap with system UI
10+
3. Bottom buttons were positioned without considering system navigation bar
11+
12+
## Solution
13+
14+
### 1. Added FocusAwareStatusBar Component
15+
Added `FocusAwareStatusBar` import and usage to ensure proper edge-to-edge handling on Android:
16+
17+
```tsx
18+
import { FocusAwareStatusBar } from '@/components/ui/focus-aware-status-bar';
19+
20+
// In component render:
21+
<FocusAwareStatusBar />
22+
```
23+
24+
The `FocusAwareStatusBar` component automatically:
25+
- Makes the navigation bar transparent with overlay behavior
26+
- Sets system UI flags to hide navigation bar when needed
27+
- Provides a seamless edge-to-edge experience
28+
29+
### 2. Added Safe Area Insets
30+
Imported and used `useSafeAreaInsets` from `react-native-safe-area-context`:
31+
32+
```tsx
33+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
34+
35+
const insets = useSafeAreaInsets();
36+
```
37+
38+
### 3. Applied Safe Area Padding
39+
Applied safe area insets to both top and bottom of the screen:
40+
41+
**Top Padding (ScrollView):**
42+
```tsx
43+
<ScrollView
44+
className="flex-1 px-4 py-6"
45+
contentContainerStyle={{ paddingBottom: Math.max(insets.bottom, 16) }}
46+
style={{ paddingTop: Math.max(insets.top, 16) }}
47+
>
48+
```
49+
50+
**Bottom Padding (Button Container):**
51+
```tsx
52+
<Box
53+
className="mb-6 flex-row space-x-4"
54+
style={{ paddingBottom: Math.max(insets.bottom, 16) }}
55+
>
56+
```
57+
58+
### 4. Safe Area Implementation Details
59+
60+
- **Minimum Padding**: Uses `Math.max(insets.bottom, 16)` to ensure at least 16px of padding even when insets are smaller
61+
- **Dynamic Padding**: Adapts to different device configurations and orientations
62+
- **Android Tablets**: Typical navigation bar height is ~48px, which gets properly handled
63+
- **Cross-Platform**: Works on both iOS and Android devices
64+
65+
## Benefits
66+
67+
1. **No UI Overlap**: Bottom buttons are no longer hidden behind the system navigation bar
68+
2. **Professional Appearance**: Provides a seamless edge-to-edge experience
69+
3. **Device Compatibility**: Works across different Android tablet sizes and configurations
70+
4. **Accessibility**: Ensures all interactive elements are accessible to users
71+
5. **Consistent UX**: Matches the behavior of other screens in the app
72+
73+
## Files Modified
74+
75+
- `/src/app/call/new/index.tsx`: Added safe area handling and FocusAwareStatusBar
76+
77+
## Testing
78+
79+
The fix should be tested on:
80+
1. Android tablets with different screen sizes
81+
2. Devices with different navigation bar heights
82+
3. Both portrait and landscape orientations
83+
4. Light and dark themes
84+
85+
## Future Considerations
86+
87+
This pattern should be applied to other screens that might have similar issues with system UI overlap on Android devices.

expo-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
/// <reference types="expo/types" />
22

3-
// NOTE: This file should not be edited and should be in your git ignore
3+
// NOTE: This file should not be edited and should be in your git ignore

jest-platform-setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ Object.defineProperty(global, 'Platform', {
1919
jest.doMock('react-native/Libraries/Utilities/Platform', () => mockPlatform);
2020

2121
// Ensure Platform is available in the global scope for React Navigation and other libs
22-
(global as any).Platform = mockPlatform;
22+
(global as any).Platform = mockPlatform;

src/api/calls/calls.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,20 @@ export const createCall = async (callData: CreateCallRequest) => {
8787
const dispatchEntries: string[] = [];
8888

8989
if (callData.dispatchUsers) {
90-
dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
90+
//dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
91+
dispatchEntries.push(...callData.dispatchUsers);
9192
}
9293
if (callData.dispatchGroups) {
93-
dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
94+
//dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
95+
dispatchEntries.push(...callData.dispatchGroups);
9496
}
9597
if (callData.dispatchRoles) {
96-
dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
98+
//dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
99+
dispatchEntries.push(...callData.dispatchRoles);
97100
}
98101
if (callData.dispatchUnits) {
99-
dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
102+
//dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
103+
dispatchEntries.push(...callData.dispatchUnits);
100104
}
101105

102106
dispatchList = dispatchEntries.join('|');
@@ -130,16 +134,20 @@ export const updateCall = async (callData: UpdateCallRequest) => {
130134
const dispatchEntries: string[] = [];
131135

132136
if (callData.dispatchUsers) {
133-
dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
137+
//dispatchEntries.push(...callData.dispatchUsers.map((user) => `U:${user}`));
138+
dispatchEntries.push(...callData.dispatchUsers);
134139
}
135140
if (callData.dispatchGroups) {
136-
dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
141+
//dispatchEntries.push(...callData.dispatchGroups.map((group) => `G:${group}`));
142+
dispatchEntries.push(...callData.dispatchGroups);
137143
}
138144
if (callData.dispatchRoles) {
139-
dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
145+
//dispatchEntries.push(...callData.dispatchRoles.map((role) => `R:${role}`));
146+
dispatchEntries.push(...callData.dispatchRoles);
140147
}
141148
if (callData.dispatchUnits) {
142-
dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
149+
//dispatchEntries.push(...callData.dispatchUnits.map((unit) => `U:${unit}`));
150+
dispatchEntries.push(...callData.dispatchUnits);
143151
}
144152

145153
dispatchList = dispatchEntries.join('|');

src/app/_layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { APIProvider } from '@/api';
2222
import { CountlyProvider } from '@/components/common/countly-provider';
2323
import { LiveKitBottomSheet } from '@/components/livekit';
2424
import { PushNotificationModal } from '@/components/push-notification/push-notification-modal';
25+
import { ToastContainer } from '@/components/toast/toast-container';
2526
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider';
2627
import { loadKeepAliveState } from '@/lib/hooks/use-keep-alive';
2728
import { loadSelectedTheme } from '@/lib/hooks/use-selected-theme';
@@ -181,6 +182,7 @@ function Providers({ children }: { children: React.ReactNode }) {
181182
<LiveKitBottomSheet />
182183
<PushNotificationModal />
183184
<FlashMessage position="top" />
185+
<ToastContainer />
184186
</BottomSheetModalProvider>
185187
</ThemeProvider>
186188
</GluestackUIProvider>

0 commit comments

Comments
 (0)