Skip to content
Open
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
7 changes: 3 additions & 4 deletions shared/chat/audio/audio-recorder.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,7 @@ const useIconAndOverlay = (p: {
const maxCancelDrift = -120
const maxLockDrift = -100
dragYSV.set(interpolate(e.translationY, [maxLockDrift, 0], [maxLockDrift, 0], Extrapolation.CLAMP))
dragXSV.set(
interpolate(e.translationX, [maxCancelDrift, 0], [maxCancelDrift, 0], Extrapolation.CLAMP)
)
dragXSV.set(interpolate(e.translationX, [maxCancelDrift, 0], [maxCancelDrift, 0], Extrapolation.CLAMP))
if (e.translationX < maxCancelDrift) {
canceledSV.set(1)
} else if (e.translationY < maxLockDrift) {
Expand Down Expand Up @@ -476,7 +474,8 @@ const useRecorder = (p: {ampSV: SVN; setShowAudioSend: (s: boolean) => void; sho
React.useEffect(() => {
return () => {
setShowAudioSend(false)
onResetRef.current()
onResetRef
.current()
.then(() => {})
.catch(() => {})
}
Expand Down
60 changes: 47 additions & 13 deletions shared/chat/conversation/header-area/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import * as C from '@/constants'
import * as Chat from '@/stores/chat'
import {getConvoState} from '@/stores/convostate'
import {useProfileState} from '@/stores/profile'
import * as Kb from '@/common-adapters'
import type {HeaderBackButtonProps} from '@react-navigation/elements'
import {HeaderLeftButton} from '@/common-adapters/header-buttons'
import {Keyboard} from 'react-native'
import type {SFSymbol} from 'sf-symbols-typescript'
// import {DebugChatDumpContext} from '@/constants/chat/debug'
import {assertionToDisplay} from '@/common-adapters/usernames'
import {useSafeAreaFrame} from 'react-native-safe-area-context'
Expand Down Expand Up @@ -96,22 +98,54 @@ const BadgeHeaderLeftArray = (p: HeaderBackButtonProps) => {
return <HeaderLeftButton badgeNumber={badgeNumber} {...p} />
}

const sfIcon = (name: SFSymbol) => ({name, type: 'sfSymbol' as const})

export const headerNavigationOptions = (route: {params?: {conversationIDKey?: string}}) => {
const conversationIDKey = route.params?.conversationIDKey ?? Chat.noConversationIDKey
return {
headerLeft: (props: HeaderBackButtonProps) => {
const {onLabelLayout, labelStyle, ...rest} = props
return (
<Chat.ChatProvider id={conversationIDKey}>
<BadgeHeaderLeftArray {...rest} />
</Chat.ChatProvider>
)
},
headerRight: () => (
<Chat.ChatProvider id={conversationIDKey}>
<HeaderAreaRight />
</Chat.ChatProvider>
),
// iOS 26: headerLeft omitted — native back button comes from tabStackOptions (headerBackVisible: true).
// BadgeHeaderUpdater in container.tsx drives unstable_headerLeftItems for the badge count.
...(!Kb.Styles.isIOS
? {
headerLeft: (props: HeaderBackButtonProps) => {
const {labelStyle, ...rest} = props
return (
<Chat.ChatProvider id={conversationIDKey}>
<BadgeHeaderLeftArray {...rest} />
</Chat.ChatProvider>
)
},
}
: {}),
// iOS 26: two separate native buttons (each gets its own glass pill).
// getConvoState lets us access dispatch without hooks since this runs outside React.
...(Kb.Styles.isIOS
? {
unstable_headerRightItems: () => [
{
icon: sfIcon('magnifyingglass'),
label: 'Search',
onPress: () => {
Keyboard.dismiss()
setTimeout(() => getConvoState(conversationIDKey).dispatch.toggleThreadSearch(), 100)
},
type: 'button' as const,
},
{
icon: sfIcon('info.circle'),
label: 'Info',
onPress: () => getConvoState(conversationIDKey).dispatch.showInfoPanel(true, undefined),
type: 'button' as const,
},
],
}
: {
headerRight: () => (
<Chat.ChatProvider id={conversationIDKey}>
<HeaderAreaRight />
</Chat.ChatProvider>
),
}),
headerTitle: () => (
<Chat.ChatProvider id={conversationIDKey}>
<HeaderBranchContainer />
Expand Down
2 changes: 1 addition & 1 deletion shared/chat/inbox-and-conversation-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const Header = () => {
canBeNull={true}
id={
// eslint-disable-next-line
params?.conversationIDKey ?? Chat.noConversationIDKey
(params as {conversationIDKey?: string} | undefined)?.conversationIDKey ?? Chat.noConversationIDKey
}
>
<Header2 />
Expand Down
26 changes: 24 additions & 2 deletions shared/chat/inbox/get-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,25 @@ import * as Kb from '@/common-adapters'
import {HeaderNewChatButton} from './new-chat-button'

const buttonWidth = 132
export default {
freezeOnBlur: false, // let it render even if not visible

const mobileOptions = Kb.Styles.isIOS
? {
// iOS 26: hidesSharedBackground prevents the glass circle around the custom button
unstable_headerRightItems: () => [
{element: <HeaderNewChatButton />, hidesSharedBackground: true, type: 'custom' as const},
],
}
: {
headerRight: () => <HeaderNewChatButton />,
headerRightContainerStyle: {
...Common.defaultNavigationOptions.headerRightContainerStyle,
minWidth: buttonWidth,
paddingRight: 8,
width: buttonWidth,
} as Kb.Styles.StylesCrossPlatform,
}

const desktopOptions = {
headerLeft: () => null,
headerLeftContainerStyle: {
...Common.defaultNavigationOptions.headerLeftContainerStyle,
Expand All @@ -18,6 +35,11 @@ export default {
paddingRight: 8,
width: buttonWidth,
} as Kb.Styles.StylesCrossPlatform,
}

export default {
freezeOnBlur: false,
...(Kb.Styles.isMobile ? mobileOptions : desktopOptions),
headerTitle: () => (
<Kb.Text type="BodyBig" center={true}>
Chats
Expand Down
117 changes: 69 additions & 48 deletions shared/chat/inbox/new-chat-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import * as C from '@/constants'
import * as Chat from '@/stores/chat'
import * as Kb from '@/common-adapters'
import {LiquidGlassView, isLiquidGlassSupported} from '@callstack/liquid-glass'

const rainbowHeight = C.isElectron ? 32 : 36
const rainbowWidth = C.isElectron ? 80 : 96
const colorBarCommon = {
height: rainbowHeight / 4,
position: 'absolute',
width: '100%',
} as const

const HeaderNewChatButton = () => {
const hide = Chat.useChatState(
Expand All @@ -15,19 +24,19 @@ const HeaderNewChatButton = () => {

if (hide) return null

return (
const rainbowButton = (
<Kb.Box2
direction="vertical"
style={styles.rainbowButtonContainer}
tooltip={`(${C.shortcutSymbol}N)`}
className="tooltip-right"
alignItems="center"
justifyContent="center"
>
<Kb.Box2 direction="vertical" style={styles.gradientContainer} pointerEvents="none">
<Kb.Box2 direction="vertical" style={styles.gradientRed} />
<Kb.Box2 direction="vertical" flex={1} style={styles.gradientOrange} />
<Kb.Box2 direction="vertical" flex={1} style={styles.gradientYellow} />
<Kb.Box2 direction="vertical" style={styles.gradientGreen} />
</Kb.Box2>
<Kb.Box2 direction="vertical" style={styles.gradientRed} />
<Kb.Box2 direction="vertical" style={styles.gradientOrange} />
<Kb.Box2 direction="vertical" style={styles.gradientYellow} />
<Kb.Box2 direction="vertical" style={styles.gradientGreen} />
<Kb.Button
label="New chat"
mode="Primary"
Expand All @@ -38,55 +47,67 @@ const HeaderNewChatButton = () => {
/>
</Kb.Box2>
)

// eslint-disable-next-line
if (C.isIOS && isLiquidGlassSupported) {
return (
<LiquidGlassView
interactive={true}
effect={'regular'}
style={{
alignContent: 'center',
borderRadius: 8,
height: rainbowHeight,
justifyContent: 'center',
padding: 8,
width: rainbowWidth,
}}
>
{rainbowButton}
</LiquidGlassView>
)
}

return rainbowButton
}

const calcBarTop = (index: number) => index * colorBarCommon.height

const styles = Kb.Styles.styleSheetCreate(
() =>
({
gradientContainer: Kb.Styles.platformStyles({
isElectron: {
height: '100%',
position: 'absolute',
width: '100%',
},
isMobile: {
bottom: Kb.Styles.isAndroid ? 5 : 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
}),
gradientGreen: Kb.Styles.platformStyles({
common: {
backgroundColor: '#3AFFAC',
borderBottomLeftRadius: Kb.Styles.borderRadius,
borderBottomRightRadius: Kb.Styles.borderRadius,
flex: 1,
},
}),
gradientOrange: {backgroundColor: '#FFAC3D'},
gradientRed: Kb.Styles.platformStyles({
common: {
backgroundColor: '#FF5D5D',
borderTopLeftRadius: Kb.Styles.borderRadius,
borderTopRightRadius: Kb.Styles.borderRadius,
flex: 1,
},
}),
gradientYellow: {backgroundColor: '#FFF75A'},
rainbowButton: Kb.Styles.platformStyles({
common: {
margin: 2,
paddingLeft: Kb.Styles.globalMargins.tiny,
paddingRight: Kb.Styles.globalMargins.tiny,
},
}),
gradientGreen: {
...colorBarCommon,
backgroundColor: '#3AFFAC',
top: calcBarTop(3),
},
gradientOrange: {
...colorBarCommon,
backgroundColor: '#FFAC3D',
top: calcBarTop(1),
},
gradientRed: {
...colorBarCommon,
backgroundColor: '#FF5D5D',
top: calcBarTop(0),
},
gradientYellow: {
...colorBarCommon,
backgroundColor: '#FFF75A',
top: calcBarTop(2),
},
rainbowButton: {
margin: 2,
paddingLeft: Kb.Styles.globalMargins.tiny,
paddingRight: Kb.Styles.globalMargins.tiny,
},
rainbowButtonContainer: Kb.Styles.platformStyles({
common: {
alignSelf: 'flex-start',
height: '100%',
borderRadius: Kb.Styles.borderRadius,
height: rainbowHeight,
overflow: 'hidden',
position: 'relative',
width: rainbowWidth,
},
isElectron: {
...Kb.Styles.desktopStyles.windowDraggingClickable,
Expand Down
1 change: 1 addition & 0 deletions shared/common-adapters/scroll-view.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export type Props = {
// mobile only
bounces?: boolean
contentInset?: {top?: number; left?: number; bottom?: number; right?: number}
contentInsetAdjustmentBehavior?: 'automatic' | 'scrollableAxes' | 'never' | 'always'
centerContent?: boolean
zoomScale?: number
minimumZoomScale?: number
Expand Down
10 changes: 7 additions & 3 deletions shared/common-adapters/text.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function Text(p: Props) {
selectable={p.selectable}
numberOfLines={p.lineClamp}
ellipsizeMode={p.lineClamp ? (p.ellipsizeMode ?? 'tail') : undefined}
suppressHighlighting={true}
>
{p.children}
</RNText>
Expand All @@ -30,6 +31,9 @@ export function Text(p: Props) {

export default Text

const styles = Styles.styleSheetCreate(() => ({
center: {textAlign: 'center'},
}) as const)
const styles = Styles.styleSheetCreate(
() =>
({
center: {textAlign: 'center'},
}) as const
)
36 changes: 1 addition & 35 deletions shared/constants/init/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils'
import {useChatState} from '@/stores/chat'
import {useConfigState} from '@/stores/config'
import {useCurrentUserState} from '@/stores/current-user'
import {useDaemonState} from '@/stores/daemon'
import {useDarkModeState} from '@/stores/darkmode'
import {useFSState} from '@/stores/fs'
Expand All @@ -21,7 +20,7 @@ import logger from '@/logger'
import {Alert, Linking} from 'react-native'
import {isAndroid} from '@/constants/platform.native'
import {wrapErrors} from '@/util/debug'
import {getTab, getVisiblePath, logState, switchTab} from '@/constants/router'
import {getTab, getVisiblePath, logState} from '@/constants/router'
import {launchImageLibraryAsync} from '@/util/expo-image-picker.native'
import {pickDocumentsAsync} from '@/util/expo-document-picker.native'
import {setupAudioMode} from '@/util/audio.native'
Expand Down Expand Up @@ -529,21 +528,6 @@ export const initPlatformListener = () => {
})
})

let _pendingFastSwitchTab: string | undefined
useRouterState.setState(s => {
s.dispatch.defer.tabLongPress = wrapErrors((tab: string) => {
if (tab !== Tabs.peopleTab) return
const accountRows = useConfigState.getState().configuredAccounts
const current = useCurrentUserState.getState().username
const row = accountRows.find(a => a.username !== current && a.hasStoredSecret)
if (row) {
_pendingFastSwitchTab = getTab() ?? undefined
useConfigState.getState().dispatch.setUserSwitching(true)
useConfigState.getState().dispatch.login(row.username, '')
}
})
})

useFSState.setState(s => {
s.dispatch.defer.pickAndUploadMobile = wrapErrors(
(type: T.FS.MobilePickType, parentPath: T.FS.Path) => {
Expand Down Expand Up @@ -675,24 +659,6 @@ export const initPlatformListener = () => {
})
}

useConfigState.subscribe((state, prevState) => {
const tab = _pendingFastSwitchTab
if (!tab) return
if (state.loggedIn && !prevState.loggedIn) {
_pendingFastSwitchTab = undefined
let attempts = 0
const trySwitch = () => {
if (attempts++ > 20) return
if (getTab()) {
switchTab(tab as Tabs.AppTab)
} else {
setTimeout(trySwitch, 100)
}
}
setTimeout(trySwitch, 100)
}
})

initSharedSubscriptions()
}

Expand Down
Loading