@planningcenter/chat-react-native 3.42.3-qa-staging.1 → 3.42.3-qa-staging.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/build/components/display/platform_modal_header_buttons.d.ts +47 -7
  2. package/build/components/display/platform_modal_header_buttons.d.ts.map +1 -1
  3. package/build/components/display/platform_modal_header_buttons.js +119 -9
  4. package/build/components/display/platform_modal_header_buttons.js.map +1 -1
  5. package/build/contexts/chat_context.d.ts +1 -0
  6. package/build/contexts/chat_context.d.ts.map +1 -1
  7. package/build/contexts/chat_context.js +7 -1
  8. package/build/contexts/chat_context.js.map +1 -1
  9. package/build/hooks/index.d.ts +1 -1
  10. package/build/hooks/index.d.ts.map +1 -1
  11. package/build/hooks/index.js +1 -1
  12. package/build/hooks/index.js.map +1 -1
  13. package/build/hooks/use_current_person.d.ts.map +1 -1
  14. package/build/hooks/use_current_person.js +1 -0
  15. package/build/hooks/use_current_person.js.map +1 -1
  16. package/build/hooks/use_direct_messages_eligible.d.ts +2 -0
  17. package/build/hooks/use_direct_messages_eligible.d.ts.map +1 -0
  18. package/build/hooks/use_direct_messages_eligible.js +9 -0
  19. package/build/hooks/use_direct_messages_eligible.js.map +1 -0
  20. package/build/hooks/use_features.d.ts +0 -1
  21. package/build/hooks/use_features.d.ts.map +1 -1
  22. package/build/hooks/use_features.js +0 -1
  23. package/build/hooks/use_features.js.map +1 -1
  24. package/build/navigation/index.d.ts +69 -173
  25. package/build/navigation/index.d.ts.map +1 -1
  26. package/build/navigation/index.js +61 -72
  27. package/build/navigation/index.js.map +1 -1
  28. package/build/screens/bug_report_screen.d.ts.map +1 -1
  29. package/build/screens/bug_report_screen.js +10 -13
  30. package/build/screens/bug_report_screen.js.map +1 -1
  31. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  32. package/build/screens/conversation_details_screen.js +11 -12
  33. package/build/screens/conversation_details_screen.js.map +1 -1
  34. package/build/screens/conversation_filters/components/conversation_filters.js +3 -3
  35. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  36. package/build/screens/conversation_filters_screen.js +2 -2
  37. package/build/screens/conversation_filters_screen.js.map +1 -1
  38. package/build/screens/conversation_screen.d.ts.map +1 -1
  39. package/build/screens/conversation_screen.js +9 -2
  40. package/build/screens/conversation_screen.js.map +1 -1
  41. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  42. package/build/screens/conversation_select_type_screen.js +4 -7
  43. package/build/screens/conversation_select_type_screen.js.map +1 -1
  44. package/build/screens/conversations/components/list_header_component.js +3 -3
  45. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  46. package/build/screens/message_report_screen.d.ts.map +1 -1
  47. package/build/screens/message_report_screen.js +14 -18
  48. package/build/screens/message_report_screen.js.map +1 -1
  49. package/build/screens/notification_settings_screen.d.ts.map +1 -1
  50. package/build/screens/notification_settings_screen.js +0 -14
  51. package/build/screens/notification_settings_screen.js.map +1 -1
  52. package/build/screens/settings_screen.js +3 -3
  53. package/build/screens/settings_screen.js.map +1 -1
  54. package/build/types/resources/person.d.ts +1 -0
  55. package/build/types/resources/person.d.ts.map +1 -1
  56. package/build/types/resources/person.js.map +1 -1
  57. package/build/utils/index.d.ts +1 -0
  58. package/build/utils/index.d.ts.map +1 -1
  59. package/build/utils/index.js +1 -0
  60. package/build/utils/index.js.map +1 -1
  61. package/build/utils/liquid_glass.d.ts +3 -0
  62. package/build/utils/liquid_glass.d.ts.map +1 -0
  63. package/build/utils/liquid_glass.js +9 -0
  64. package/build/utils/liquid_glass.js.map +1 -0
  65. package/package.json +3 -3
  66. package/src/__tests__/hooks/use_direct_messages_eligible.test.tsx +77 -0
  67. package/src/__tests__/utils/liquid_glass.ts +40 -0
  68. package/src/components/display/platform_modal_header_buttons.tsx +254 -13
  69. package/src/contexts/chat_context.tsx +8 -0
  70. package/src/hooks/index.ts +1 -1
  71. package/src/hooks/use_current_person.ts +1 -0
  72. package/src/hooks/use_direct_messages_eligible.ts +11 -0
  73. package/src/hooks/use_features.ts +0 -1
  74. package/src/navigation/index.tsx +149 -166
  75. package/src/screens/bug_report_screen.tsx +16 -15
  76. package/src/screens/conversation_details_screen.tsx +11 -17
  77. package/src/screens/conversation_filters/components/conversation_filters.tsx +3 -3
  78. package/src/screens/conversation_filters_screen.tsx +2 -2
  79. package/src/screens/conversation_screen.tsx +10 -2
  80. package/src/screens/conversation_select_type_screen.tsx +4 -7
  81. package/src/screens/conversations/components/list_header_component.tsx +3 -3
  82. package/src/screens/message_report_screen.tsx +20 -21
  83. package/src/screens/notification_settings_screen.tsx +1 -21
  84. package/src/screens/settings_screen.tsx +3 -3
  85. package/src/types/resources/person.ts +1 -0
  86. package/src/utils/index.ts +1 -0
  87. package/src/utils/liquid_glass.ts +12 -0
  88. package/build/hooks/use_direct_messages_enabled.d.ts +0 -2
  89. package/build/hooks/use_direct_messages_enabled.d.ts.map +0 -1
  90. package/build/hooks/use_direct_messages_enabled.js +0 -16
  91. package/build/hooks/use_direct_messages_enabled.js.map +0 -1
  92. package/src/hooks/use_direct_messages_enabled.ts +0 -23
@@ -1,18 +1,19 @@
1
- import { HeaderBackButton } from '@react-navigation/elements'
2
1
  import { StaticParamList } from '@react-navigation/native'
3
2
  import {
4
3
  createNativeStackNavigator,
5
4
  NativeStackHeaderRightProps,
5
+ NativeStackNavigationOptions,
6
6
  } from '@react-navigation/native-stack'
7
7
  import { CardStyleInterpolators } from '@react-navigation/stack'
8
8
  import React from 'react'
9
- import { Platform } from 'react-native'
10
- import { Icon } from '../components'
11
9
  import {
12
- HeaderDoneButton,
13
- HeaderTextButton,
10
+ composeOptions,
11
+ createMinimalHeaderBackButton,
12
+ withMinimalBack,
13
+ withRightClose,
14
+ withRightDone,
14
15
  } from '../components/display/platform_modal_header_buttons'
15
- import { useDirectMessagesEnabled, useQualifiedByAge } from '../hooks'
16
+ import { useDirectMessagesEligible, useQualifiedByAge } from '../hooks'
16
17
  import {
17
18
  AttachmentActionsScreen,
18
19
  AttachmentActionsScreenOptions,
@@ -79,69 +80,66 @@ import {
79
80
  SystemMessagePeopleScreenOptions,
80
81
  } from '../screens/system_message_people_screen'
81
82
  import { TeamConversationScreen } from '../screens/team_conversation_screen'
83
+ import { isLiquidGlassEnabled } from '../utils/liquid_glass'
82
84
  import { ScreenLayoutWithChatAccessGate } from './screenLayout'
83
85
 
84
- const HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES = {
85
- marginLeft: Platform.select({ ios: -8, default: -3 }),
86
- marginRight: Platform.select({ ios: 0, default: 30 }),
87
- }
86
+ const globalScreenOptions: () => NativeStackNavigationOptions = () => ({
87
+ headerBackButtonDisplayMode: 'minimal',
88
+ ...(isLiquidGlassEnabled() ? { headerShadowVisible: false } : {}),
89
+ })
88
90
 
89
91
  export const NewConversationStack = createNativeStackNavigator({
90
92
  initialRouteName: 'ConversationNewEntry',
91
- screenOptions: {
92
- headerBackButtonDisplayMode: 'minimal',
93
- },
93
+ screenOptions: globalScreenOptions,
94
94
  screenLayout: ScreenLayoutWithChatAccessGate,
95
95
  screens: {
96
96
  ConversationNewEntry: {
97
97
  screen: ConversationNewEntryScreen,
98
- options: ({ navigation }) => ({
99
- title: 'New conversation',
100
- headerRight: (props: NativeStackHeaderRightProps) => (
101
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Cancel" />
98
+ options: ({ navigation }) =>
99
+ composeOptions(
100
+ {
101
+ title: 'New conversation',
102
+ headerBackVisible: false,
103
+ },
104
+ withRightClose({ onPress: navigation.goBack })
102
105
  ),
103
- headerBackVisible: false,
104
- }),
105
106
  },
106
107
  ConversationSelectGroupRecipients: {
107
108
  screen: ConversationSelectGroupRecipientsScreen,
108
- options: ({ navigation, route }) => ({
109
- title: 'New conversation',
110
- headerRight: (props: NativeStackHeaderRightProps) => (
111
- <HeaderTextButton
112
- {...props}
113
- onPress={() => navigation.popTo('Conversations', route.params)}
114
- title="Cancel"
115
- />
109
+ options: ({ navigation, route }) =>
110
+ composeOptions(
111
+ {
112
+ title: 'New conversation',
113
+ },
114
+ withRightClose({
115
+ onPress: () => navigation.popTo('Conversations', route.params),
116
+ })
116
117
  ),
117
- }),
118
118
  },
119
119
  ConversationSelectTeamsILeadRecipients: {
120
120
  screen: ConversationSelectTeamsILeadRecipientsScreen,
121
- options: ({ navigation, route }) => ({
122
- title: 'New conversation',
123
- headerRight: (props: NativeStackHeaderRightProps) => (
124
- <HeaderTextButton
125
- {...props}
126
- onPress={() => navigation.popTo('Conversations', route.params)}
127
- title="Cancel"
128
- />
121
+ options: ({ navigation, route }) =>
122
+ composeOptions(
123
+ {
124
+ title: 'New conversation',
125
+ },
126
+ withRightClose({
127
+ onPress: () => navigation.popTo('Conversations', route.params),
128
+ })
129
129
  ),
130
- }),
131
130
  },
132
131
  ConversationSelectDirectMessageRecipients: {
133
132
  screen: ConversationSelectDirectMessageRecipientsScreen,
134
- if: useDirectMessagesEnabled,
135
- options: ({ navigation, route }) => ({
136
- title: 'New conversation',
137
- headerRight: (props: NativeStackHeaderRightProps) => (
138
- <HeaderTextButton
139
- {...props}
140
- onPress={() => navigation.popTo('Conversations', route.params)}
141
- title="Cancel"
142
- />
133
+ if: useDirectMessagesEligible,
134
+ options: ({ navigation, route }) =>
135
+ composeOptions(
136
+ {
137
+ title: 'New conversation',
138
+ },
139
+ withRightClose({
140
+ onPress: () => navigation.popTo('Conversations', route.params),
141
+ })
143
142
  ),
144
- }),
145
143
  },
146
144
  ConversationFilterRecipients: {
147
145
  screen: ConversationFilterRecipientsScreen,
@@ -149,21 +147,20 @@ export const NewConversationStack = createNativeStackNavigator({
149
147
  },
150
148
  ConversationNew: {
151
149
  screen: ConversationNewScreen,
152
- options: ({ navigation, route }) => ({
153
- title: 'New conversation',
154
- headerLeft: () => null,
155
- headerRight: (props: NativeStackHeaderRightProps) => (
156
- <HeaderTextButton
157
- {...props}
158
- onPress={() => {
150
+ options: ({ navigation, route }) =>
151
+ composeOptions(
152
+ {
153
+ title: 'New conversation',
154
+ headerLeft: () => null,
155
+ },
156
+ withRightClose({
157
+ onPress: () => {
159
158
  const { chat_group_graph_id, group_source_app_name } =
160
159
  route.params as ConversationSelectRecipientsParams
161
160
  navigation.popTo('Conversations', { chat_group_graph_id, group_source_app_name })
162
- }}
163
- title="Cancel"
164
- />
161
+ },
162
+ })
165
163
  ),
166
- }),
167
164
  },
168
165
  AvatarPicker: {
169
166
  screen: AvatarPickerScreen,
@@ -173,24 +170,19 @@ export const NewConversationStack = createNativeStackNavigator({
173
170
  })
174
171
 
175
172
  export const ChatStack = createNativeStackNavigator({
176
- screenOptions: {
177
- headerBackButtonDisplayMode: 'minimal',
178
- },
173
+ screenOptions: globalScreenOptions,
179
174
  screenLayout: ScreenLayoutWithChatAccessGate,
180
175
  screens: {
181
176
  Conversations: {
182
177
  screen: ConversationsScreen,
183
- options: ({ route, navigation }) => ({
184
- headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
185
- headerBackVisible: false,
186
- headerRight: (props: NativeStackHeaderRightProps) => (
187
- <HeaderBackButton
188
- backImage={() => <Icon name="general.x" size={18} color={props.tintColor} />}
189
- onPress={navigation.goBack}
190
- {...props}
191
- />
178
+ options: ({ route, navigation }) =>
179
+ composeOptions(
180
+ {
181
+ headerTitle: (route.params as { title?: string })?.title ?? 'Chat',
182
+ headerBackVisible: false,
183
+ },
184
+ withRightClose({ onPress: navigation.goBack })
192
185
  ),
193
- }),
194
186
  },
195
187
  ConversationFilters: {
196
188
  screen: ConversationFiltersScreen,
@@ -198,61 +190,48 @@ export const ChatStack = createNativeStackNavigator({
198
190
  },
199
191
  Conversation: {
200
192
  screen: ConversationScreen,
201
- options: ({ route, navigation }) => ({
202
- headerTitle: (props: NativeStackHeaderRightProps) => {
203
- const { conversation_id, title, badge, deleted, muted } =
204
- route.params as ConversationRouteProps
193
+ options: ({ route, navigation }) =>
194
+ composeOptions(
195
+ {
196
+ headerTitle: (props: NativeStackHeaderRightProps) => {
197
+ const { conversation_id, title, badge, deleted, muted } =
198
+ route.params as ConversationRouteProps
205
199
 
206
- return (
207
- <ConversationScreenTitle
208
- conversation_id={conversation_id}
209
- badge={badge}
210
- deleted={deleted}
211
- muted={muted}
212
- {...props}
213
- >
214
- {title ?? 'Conversation'}
215
- </ConversationScreenTitle>
216
- )
217
- },
218
- headerRight: (props: NativeStackHeaderRightProps) => (
219
- <HeaderBackButton
220
- backImage={() => <Icon name="general.x" size={18} color={props.tintColor} />}
221
- onPress={() => navigation.getParent()?.goBack()}
222
- />
200
+ return (
201
+ <ConversationScreenTitle
202
+ conversation_id={conversation_id}
203
+ badge={badge}
204
+ deleted={deleted}
205
+ muted={muted}
206
+ {...props}
207
+ >
208
+ {title ?? 'Conversation'}
209
+ </ConversationScreenTitle>
210
+ )
211
+ },
212
+ headerLeft: createMinimalHeaderBackButton({
213
+ onPress: () => {
214
+ const params = route.params as ConversationRouteProps
215
+ if ((params as ConversationFiltersParams)?.chat_group_graph_id) {
216
+ // Ensure that conversations with a graph id pass them back to the conversation list
217
+ const { chat_group_graph_id } = params
218
+ navigation.popTo('Conversations', { chat_group_graph_id })
219
+ } else {
220
+ navigation.goBack()
221
+ }
222
+ },
223
+ }),
224
+ },
225
+ withRightClose({ onPress: () => navigation.getParent()?.goBack() })
223
226
  ),
224
- headerLeft: props => (
225
- <HeaderBackButton
226
- style={HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES}
227
- displayMode="minimal"
228
- onPress={() => {
229
- const params = route.params as ConversationRouteProps
230
- if ((params as ConversationFiltersParams)?.chat_group_graph_id) {
231
- // Ensure that conversations with a graph id pass them back to the conversation list
232
- const { chat_group_graph_id } = params
233
- navigation.popTo('Conversations', { chat_group_graph_id })
234
- } else {
235
- navigation.goBack()
236
- }
237
- }}
238
- {...props}
239
- />
240
- ),
241
- }),
242
227
  },
243
228
  ConversationReply: {
244
229
  screen: ConversationScreen,
245
- options: ({ route, navigation }) => ({
246
- title: (route.params as ConversationRouteProps)?.title ?? 'Reply',
247
- headerLeft: props => (
248
- <HeaderBackButton
249
- style={HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES}
250
- displayMode="minimal"
251
- onPress={() => navigation.goBack()}
252
- {...props}
253
- />
230
+ options: ({ route, navigation }) =>
231
+ composeOptions(
232
+ { title: (route.params as ConversationRouteProps)?.title ?? 'Reply' },
233
+ withMinimalBack({ onPress: navigation.goBack })
254
234
  ),
255
- }),
256
235
  },
257
236
  TeamConversation: {
258
237
  screen: TeamConversationScreen,
@@ -265,13 +244,14 @@ export const ChatStack = createNativeStackNavigator({
265
244
  },
266
245
  ConversationDetails: {
267
246
  screen: ConversationDetailsScreen,
268
- options: ({ navigation }) => ({
269
- presentation: 'modal',
270
- title: 'Conversation details',
271
- headerRight: (props: NativeStackHeaderRightProps) => (
272
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
247
+ options: ({ navigation }) =>
248
+ composeOptions(
249
+ {
250
+ presentation: 'modal',
251
+ title: 'Conversation details',
252
+ },
253
+ withRightDone({ onPress: navigation.goBack })
273
254
  ),
274
- }),
275
255
  },
276
256
  AvatarPicker: {
277
257
  screen: AvatarPickerScreen,
@@ -279,38 +259,43 @@ export const ChatStack = createNativeStackNavigator({
279
259
  },
280
260
  ChatSettings: {
281
261
  screen: SettingsScreen,
282
- options: ({ navigation }) => ({
283
- title: 'Chat settings',
284
- headerBackVisible: false,
285
- headerRight: (props: NativeStackHeaderRightProps) => (
286
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
287
- ),
288
- }),
262
+ options: ({ navigation }) =>
263
+ composeOptions({ title: 'Chat settings' }, withMinimalBack({ onPress: navigation.goBack })),
289
264
  },
290
265
  NotificationSettings: {
291
266
  screen: NotificationSettingsScreen,
292
- options: ({ navigation }) => ({
293
- title: 'Chat',
294
- headerBackVisible: false,
295
- headerRight: (props: NativeStackHeaderRightProps) => (
296
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
297
- ),
298
- }),
267
+ options: ({ navigation }) =>
268
+ navigation.getState().index === 0
269
+ ? composeOptions(
270
+ { title: 'Chat notifications' },
271
+ withRightClose({ onPress: navigation.goBack })
272
+ )
273
+ : composeOptions(
274
+ { title: 'Chat notifications' },
275
+ withMinimalBack({ onPress: navigation.goBack })
276
+ ),
299
277
  },
300
278
  PreferredAppSelection: {
301
279
  screen: PreferredAppSelectionScreen,
302
- options: {
303
- title: 'Preferred app',
304
- },
280
+ options: ({ navigation }) =>
281
+ composeOptions({ title: 'Preferred app' }, withMinimalBack({ onPress: navigation.goBack })),
305
282
  },
306
283
  GroupNotificationSettings: {
307
284
  screen: GroupNotificationSettingsScreen,
308
- options: ({ route, navigation }) => ({
309
- title: (route.params as { title?: string })?.title || 'Group Settings',
310
- headerRight: (props: NativeStackHeaderRightProps) => (
311
- <HeaderDoneButton {...props} navigation={navigation} />
312
- ),
313
- }),
285
+ options: ({ route, navigation }) => {
286
+ const title = (route.params as { title?: string })?.title || 'Group Settings'
287
+
288
+ // The dismiss button only shows when this is the entry screen (e.g.
289
+ // deep links); deeper in the stack the back button covers dismissal.
290
+ return navigation.getState().index === 0
291
+ ? composeOptions(
292
+ {
293
+ title,
294
+ },
295
+ withRightClose({ onPress: navigation.goBack })
296
+ )
297
+ : composeOptions({ title }, withMinimalBack({ onPress: navigation.goBack }))
298
+ },
314
299
  },
315
300
  GroupNotificationLevelSelect: {
316
301
  screen: GroupNotificationLevelSelectScreen,
@@ -331,17 +316,14 @@ export const ChatStack = createNativeStackNavigator({
331
316
  GroupConversationNew: {
332
317
  screen: ConversationNewScreen,
333
318
  if: useQualifiedByAge,
334
- options: ({ navigation }) => ({
335
- title: 'New conversation',
336
- headerLeft: () => null,
337
- headerRight: props => (
338
- <HeaderTextButton
339
- {...props}
340
- onPress={() => navigation.getParent()?.goBack()}
341
- title="Cancel"
342
- />
319
+ options: ({ navigation }) =>
320
+ composeOptions(
321
+ {
322
+ title: 'New conversation',
323
+ headerLeft: () => null,
324
+ },
325
+ withRightClose({ onPress: () => navigation.getParent()?.goBack() })
343
326
  ),
344
- }),
345
327
  },
346
328
  SendGiphy: {
347
329
  screen: SendGiphyScreen,
@@ -382,14 +364,15 @@ export const ChatStack = createNativeStackNavigator({
382
364
  },
383
365
  GetHelp: {
384
366
  screen: GetHelpScreen,
385
- options: ({ navigation }) => ({
386
- headerTitle: 'Get help',
387
- headerBackVisible: false,
388
- presentation: 'modal',
389
- headerRight: props => (
390
- <HeaderTextButton {...props} onPress={navigation.goBack} title="Close" />
367
+ options: ({ navigation }) =>
368
+ composeOptions(
369
+ {
370
+ headerTitle: 'Get help',
371
+ headerBackVisible: false,
372
+ presentation: 'modal',
373
+ },
374
+ withRightClose({ onPress: navigation.goBack })
391
375
  ),
392
- }),
393
376
  },
394
377
  NotFound: {
395
378
  screen: NotFound,
@@ -4,7 +4,7 @@ import type {
4
4
  NativeStackScreenProps,
5
5
  } from '@react-navigation/native-stack'
6
6
  import { startsWith } from 'lodash'
7
- import React, { useCallback, useLayoutEffect, useState } from 'react'
7
+ import React, { useCallback, useState } from 'react'
8
8
  import {
9
9
  View,
10
10
  StyleSheet,
@@ -25,8 +25,10 @@ import {
25
25
  KeyboardView,
26
26
  } from '../components'
27
27
  import {
28
+ composeOptions,
28
29
  HeaderDismissButton,
29
- HeaderTextButton,
30
+ useHeaderRight,
31
+ withLeftClose,
30
32
  } from '../components/display/platform_modal_header_buttons'
31
33
  import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
32
34
  import { DefaultLoading } from '../components/page/loading'
@@ -55,11 +57,11 @@ enum BUG_TYPE_OPTIONS {
55
57
 
56
58
  export const BugReportScreenOptions = ({
57
59
  navigation,
58
- }: NativeStackScreenProps<any>): NativeStackNavigationOptions => ({
59
- presentation: 'modal',
60
- title: 'Report a bug',
61
- headerLeft: () => <HeaderDismissButton title="Cancel" onPress={() => navigation.goBack()} />,
62
- })
60
+ }: NativeStackScreenProps<any>): NativeStackNavigationOptions =>
61
+ composeOptions(
62
+ { presentation: 'modal', title: 'Report a bug' },
63
+ withLeftClose({ onPress: () => navigation.goBack() })
64
+ )
63
65
 
64
66
  interface Attachment {
65
67
  id: string
@@ -156,14 +158,13 @@ export function BugReportScreen() {
156
158
  return ImagePicker.openImageLibraryAsync().then(result => uploadImagePickerResult(result))
157
159
  }
158
160
 
159
- useLayoutEffect(() => {
160
- navigation.setOptions({
161
- // eslint-disable-next-line react/no-unstable-nested-components
162
- headerRight: () => (
163
- <HeaderTextButton title="Submit" onPress={handleSubmit} disabled={!formValid} />
164
- ),
165
- })
166
- }, [formValid, handleSubmit, navigation])
161
+ useHeaderRight({
162
+ icon: 'general.message',
163
+ accessibilityLabel: 'Submit',
164
+ variant: 'fill',
165
+ onPress: handleSubmit,
166
+ disabled: !formValid,
167
+ })
167
168
 
168
169
  if (status === 'pending') {
169
170
  return (
@@ -38,7 +38,7 @@ import {
38
38
  type TextStyle,
39
39
  } from '../components'
40
40
  import { ConversationAvatar } from '../components/display/conversation_avatar'
41
- import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
41
+ import { useHeaderRight } from '../components/display/platform_modal_header_buttons'
42
42
  import { ButtonAppearanceUnion } from '../components/display/utils/button_colors'
43
43
  import { useSuspensePaginator, useTheme } from '../hooks'
44
44
  import {
@@ -222,24 +222,18 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
222
222
  [name, productName, resourceType, styles.headerTitleBadge, styles.headerTitleContainer]
223
223
  )
224
224
 
225
- const HeaderRight = useCallback(() => {
226
- return (
227
- <HeaderTextButton
228
- onPress={() => {
229
- saveTitle({ title: trimmedTitle || conversation.title })
230
- navigation.goBack()
231
- }}
232
- title="Done"
233
- />
234
- )
235
- }, [conversation.title, navigation, saveTitle, trimmedTitle])
225
+ useHeaderRight({
226
+ icon: 'general.check',
227
+ accessibilityLabel: 'Done',
228
+ onPress: () => {
229
+ saveTitle({ title: trimmedTitle || conversation.title })
230
+ navigation.goBack()
231
+ },
232
+ })
236
233
 
237
234
  useEffect(() => {
238
- navigation.setOptions({
239
- headerRight: HeaderRight,
240
- headerTitle: HeaderTitle,
241
- })
242
- }, [HeaderRight, HeaderTitle, navigation])
235
+ navigation.setOptions({ headerTitle: HeaderTitle })
236
+ }, [HeaderTitle, navigation])
243
237
 
244
238
  const listData = [
245
239
  {
@@ -4,7 +4,7 @@ import { FlatList } from 'react-native-gesture-handler'
4
4
  import { Heading } from '../../../components'
5
5
  import {
6
6
  useAtFontScaleBreakpoint,
7
- useDirectMessagesEnabled,
7
+ useDirectMessagesEligible,
8
8
  useHasDirectMessages,
9
9
  useTheme,
10
10
  } from '../../../hooks'
@@ -59,9 +59,9 @@ export const ConversationFilters = () => {
59
59
  const { setScrollOffset, params } = useContext(FilterContext)
60
60
  const { chat_group_graph_id, group_source_app_name = '', show_direct_messages } = params
61
61
 
62
- const directMessagesEnabled = useDirectMessagesEnabled()
62
+ const directMessagesEligible = useDirectMessagesEligible()
63
63
  const hasDirectMessages = useHasDirectMessages()
64
- const canFilterByDMs = directMessagesEnabled && hasDirectMessages
64
+ const canFilterByDMs = directMessagesEligible && hasDirectMessages
65
65
 
66
66
  const activeFilter: FilterTypes = useMemo(() => {
67
67
  if (chat_group_graph_id) {
@@ -1,5 +1,5 @@
1
1
  import { useHeaderHeight } from '@react-navigation/elements'
2
- import { createComponentForStaticNavigation, RouteProp, useRoute } from '@react-navigation/native'
2
+ import { RouteProp, useRoute } from '@react-navigation/native'
3
3
  import { createNativeStackNavigator } from '@react-navigation/native-stack'
4
4
  import React, { useCallback } from 'react'
5
5
  import { LayoutChangeEvent, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
@@ -58,7 +58,7 @@ const FilterNavigator = createNativeStackNavigator<ConversationFilterStackParamL
58
58
  },
59
59
  })
60
60
 
61
- const Filters = createComponentForStaticNavigation(FilterNavigator, 'Filters')
61
+ const Filters = FilterNavigator.getComponent()
62
62
 
63
63
  export const ConversationFiltersScreen = (_props: ConversationFiltersScreenProps) => {
64
64
  const styles = useStyles()
@@ -9,7 +9,7 @@ import {
9
9
  useRoute,
10
10
  } from '@react-navigation/native'
11
11
  import React, { useCallback, useEffect, useRef, useState } from 'react'
12
- import { FlatList, Platform, StyleSheet, View } from 'react-native'
12
+ import { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
13
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
14
14
  import { Badge, Icon, Text } from '../components'
15
15
  import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
@@ -25,6 +25,7 @@ import { ReplyShadowMessage } from '../components/conversation/reply_shadow_mess
25
25
  import { SystemMessage } from '../components/conversation/system_message'
26
26
  import { TypingIndicator } from '../components/conversation/typing_indicator'
27
27
  import { KeyboardView } from '../components/display/keyboard_view'
28
+ import { useHeaderSlotReserve } from '../components/display/platform_modal_header_buttons'
28
29
  import BlankState from '../components/primitive/blank_state_primitive'
29
30
  import { ConversationContextProvider } from '../contexts/conversation_context'
30
31
  import { useTheme } from '../hooks'
@@ -45,6 +46,7 @@ import { ConversationBadgeResource } from '../types/resources/conversation_badge
45
46
  import { MessageResource } from '../types/resources/message'
46
47
  import { getRelativeDateStatus } from '../utils/date'
47
48
  import { groupMessages, type DateSeparator } from '../utils/group_messages'
49
+ import { isLiquidGlassEnabled } from '../utils/liquid_glass'
48
50
  import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../utils/styles'
49
51
  import { isSystemMessage } from '../utils/system_messages'
50
52
 
@@ -374,11 +376,17 @@ export const ConversationScreenTitle = ({
374
376
  }
375
377
 
376
378
  const usePressableHeaderStyle = () => {
379
+ const { width } = useWindowDimensions()
380
+ const slotReserve = useHeaderSlotReserve()
381
+ const headerContainerStyle = isLiquidGlassEnabled()
382
+ ? { maxWidth: width - slotReserve * 2 }
383
+ : { marginRight: Platform.select({ default: 20, android: 16 }) }
384
+
377
385
  return StyleSheet.create({
378
386
  container: {
379
387
  alignItems: Platform.select({ android: 'flex-start', default: 'center' }),
380
- marginRight: Platform.select({ ios: 20, default: 16 }),
381
388
  flex: 1,
389
+ ...headerContainerStyle,
382
390
  },
383
391
  titleWrapper: {
384
392
  alignItems: 'center',
@@ -2,7 +2,6 @@ import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
2
  import React, { useLayoutEffect } from 'react'
3
3
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
4
4
  import { useCurrentPerson } from '../hooks/use_current_person'
5
- import { availableFeatures, useFeatures } from '../hooks/use_features'
6
5
  import { useConversationTypeAccess } from '../hooks/use_new_conversation_entry'
7
6
  import type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
8
7
  import { AppName } from '../types/resources/app_name'
@@ -28,17 +27,15 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
28
27
  const navigation = useNavigation()
29
28
  const { canCreateGroupsConversations, canCreateServicesConversations } =
30
29
  useConversationTypeAccess()
31
- const { featureEnabled } = useFeatures()
32
- const { directMessagesDisabled, under_18 } = useCurrentPerson()
30
+ const { directMessagesDisabled, directMessagesEligible } = useCurrentPerson()
33
31
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
34
32
  route.params || {}
35
33
 
36
34
  const filterParams = { chat_group_graph_id, group_source_app_name }
37
- const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)
38
- const showDirectMessageOption = dmFeatureEnabled && !under_18
35
+ const showDirectMessageOption = directMessagesEligible
39
36
 
40
- // sheetAllowedDetents depends on the DM feature flag, which isn't known until render, so it's
41
- // set here instead of in the static ConversationSelectTypeScreenOptions. useLayoutEffect applies
37
+ // sheetAllowedDetents depends on DM eligibility, which isn't known until render, so it's set
38
+ // here instead of in the static ConversationSelectTypeScreenOptions. useLayoutEffect applies
42
39
  // it before paint so the sheet never visibly resizes after opening.
43
40
  useLayoutEffect(() => {
44
41
  navigation.setOptions({ sheetAllowedDetents: showDirectMessageOption ? [0.3] : [0.25] })