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
5 changes: 5 additions & 0 deletions shared/chat/conversation/thread-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {clearChatTimeCache} from '@/util/timestamp'
import {findLast} from '@/util/arrays'
import {ignorePromise} from '@/constants/utils'
import {RPCError} from '@/util/errors'
import {persistRoute} from '@/util/storeless-actions'
import {uint8ArrayToString} from '@/util/uint8array'
import {useEngineActionListener} from '@/engine/action-listener'
import {useCurrentUserState} from '@/stores/current-user'
Expand Down Expand Up @@ -868,6 +869,10 @@ const loadConversationThreadMessages = (
if (error instanceof RPCError) {
logger.warn(`loadMoreMessages: error: ${error.desc}`)
if (error.code === T.RPCGen.StatusCode.scchatnotinteam) {
// We're no longer in this conv's team. Clear the persisted last-route
// (ui.routeState2) so app startup doesn't keep restoring and reloading
// this conv, which would re-trigger this error on every launch.
persistRoute(true, true, () => useConfigState.getState().startup.loaded)
navigateToInbox(true, 'maybeKickedFromTeam')
}
if (error.code !== T.RPCGen.StatusCode.scteamreaderror) {
Expand Down
7 changes: 6 additions & 1 deletion shared/constants/init/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ const loadStartupDetails = async () => {
] as const)

let conversation: T.Chat.ConversationIDKey | undefined
let conversationUid = ''
let followUser = ''
let link = ''
let tab = ''
Expand All @@ -232,11 +233,14 @@ const loadStartupDetails = async () => {
try {
const item = JSON.parse(routeState) as
| undefined
| {param?: {selectedConversationIDKey?: unknown}; routeName?: string}
| {param?: {selectedConversationIDKey?: unknown}; routeName?: string; uid?: unknown}
if (item) {
const _convo = item.param?.selectedConversationIDKey || undefined
if (typeof _convo === 'string') {
conversation = _convo
if (typeof item.uid === 'string') {
conversationUid = item.uid
}
logger.info('initialState: routeState', conversation)
}
const _rn = item.routeName || undefined
Expand All @@ -256,6 +260,7 @@ const loadStartupDetails = async () => {

useConfigState.getState().dispatch.setStartupDetails({
conversation: conversation ?? noConversationIDKey,
conversationUid,
followUser,
link,
tab: tab as Tabs.Tab,
Expand Down
8 changes: 8 additions & 0 deletions shared/router-v2/linking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as Tabs from '@/constants/tabs'
import {isSplit} from '@/constants/chat/layout'
import {isValidConversationIDKey} from '@/constants/types/chat/common'
import {useConfigState} from '@/stores/config'
import {useCurrentUserState} from '@/stores/current-user'
import type * as UsePushStateType from '@/stores/push'
import type {LinkingOptions} from '@react-navigation/native'
import type {RootParamList} from './route-params'
Expand Down Expand Up @@ -261,6 +262,13 @@ export const createLinkingConfig = (
startupConversation = ''
}

// Only restore a conv that belongs to the logged-in account; see persistRoute
// (ui.routeState2 is device-global, so it can hold another account's conv).
const {uid: currentUid} = useCurrentUserState.getState()
if (startupConversation && startup.conversationUid && startup.conversationUid !== currentUid) {
startupConversation = ''
}

// Lazy-require to break require cycle: linking.tsx → push.native.tsx → linking.tsx
const {usePushState} = require('@/stores/push') as typeof UsePushStateType
const pushState = usePushState.getState()
Expand Down
3 changes: 3 additions & 0 deletions shared/stores/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ type Store = T.Immutable<{
startup: {
loaded: boolean
conversation: T.Chat.ConversationIDKey
// uid of the account that persisted `conversation` (from ui.routeState2).
// Used to avoid replaying a conversation under a different account.
conversationUid?: string
followUser: string
link: string
tab?: Tab
Expand Down
7 changes: 6 additions & 1 deletion shared/util/storeless-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Alert, Linking} from 'react-native'
import {showShareActionSheet as showShareActionSheetImpl} from '@/util/platform-specific'
import {getTab, getVisiblePath} from '@/constants/router'
import {peopleTab} from '@/constants/tabs'
import {useCurrentUserState} from '@/stores/current-user'

export const copyToClipboard = (text: string) => {
if (isMobile) {
Expand Down Expand Up @@ -100,7 +101,11 @@ export const persistRoute = (clear: boolean, immediate: boolean, isStartupLoaded
}
return false
})
const next = JSON.stringify({param, routeName})
// Stamp the persisted route with the current uid. ui.routeState2 is stored
// device-globally (not per-account), so on startup we must only restore a
// conversation that belongs to the account we end up logged in as.
const {uid} = useCurrentUserState.getState()
const next = JSON.stringify({param, routeName, uid})
if (lastPersist === next) {
return
}
Expand Down